更新作为 Angular2 中 formArray 中的文件输入的 formControl [英] Update a formControl that is a file input in a formArray in Angular2

查看:21
本文介绍了更新作为 Angular2 中 formArray 中的文件输入的 formControl的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下代码:

import { Component, OnInit, ElementRef } from '@angular/core';从@angular/forms"导入 { FormArray、FormBuilder、FormControl、FormGroup、Validators}@零件({选择器:'app-root',templateUrl: './app.component.html',styleUrls: ['./app.component.css']})导出类 AppComponent 实现 OnInit {显示排序:布尔值 = 假;表格:表格组;名称:表单控件;sortSelf:表单控件;sortItem:FormArray;locationItems:FormArray;构造函数(私有_fb:FormBuilder,私有_elementRef:ElementRef){}ngOnInit(): 无效 {this.sortItem = this._fb.array([this.initSort()]);this.form = this._fb.group({sortItem: this.sortItem});}initSort() {返回 this._fb.group({locationPicture: new FormControl('', []),locationItems: this._fb.array([this.initSortItems()])})}initSortItems() {返回 this._fb.group({itemPicture: new FormControl('', [])})}添加排序(){this.sortItem.push(this.initSort());}addSortLocationItem(i?: number, t?: number) {const 控件:FormArray = this.sortItem.at(i).get('locationItems');control.push(this.initSortItems());}showImage(event, level?: string, i?: number, t?: number){让文件 = event.target.files[0];if(level === 'locationPicture'){(<FormArray>this.sortItem.at(i)).controls['locationPicture'].setValue(file, {onlySelf: true});}别的{(<FormArray>this.sortItem.at(i).get('locationItems')).at(t).get('itemPicture').setValue(file, {onlySelf: true});}}下一个(值,有效:布尔值){console.log(`这是值 ${JSON.stringify(value, null, 4)}`);}}

标记:

<form class="" action="index.html" method="post" [formGroup]="form" (ngSubmit)="next(form.value, form.valid)"><div class="form-group"><div formArrayName="sortItem" class=""><div class="top-buffer-small"><a (click)="addSort()" style="cursor: default">添加排序位置 +</a>

<div *ngFor="let sortLocation of sortItem.controls; let i=index"><div [formGroupName]="i" class=""><div class="form-group"><label>位置图片</label><input type="file" formControlName="locationPicture" class="form-control locationPicture" accept="image/*" capture="camera" (change)="showImage($event, 'locationPicture', i, t)"><!-- <input type="file" formControlName="locationPicture" (change)="showImage($event)"/>--><img src="" alt="" class="location-image" width="80" height="80"><small class="form-text text-muted" [hidden]="sortItem.controls[i].controls.locationPicture.valid">图片为必填项</小>

<div formArrayName="locationItems" class="col-md-10 col-md-offset-1"><div class="row"><a (click)="addSortLocationItem(i,t)" style="cursor: default">添加项目 +</a>

<!-- <div class="from-group" *ngFor="let eachItem of form.controls.sortItem.controls[i].controls.locationItems.controls; let t=index">--><div class="form-group" *ngFor="let eachItem of sortLocation.get('locationItems').controls; let t=index"><div [formGroupName]="t"><div class="form-group"><label>项目图片</label><input type="file" formControlName="itemPicture" class="form-control itemPicture" capture="camera" (change)="showImage($event, 'itemPicture', i, t)"><img src="" alt="" class="item-image" width="80" height="80"><small class="form-text text-muted" [hidden]="sortItem.controls[i].controls.locationItems.controls[t].controls.itemPicture.valid">图片为必填项</小>

<div class="clearfix"></div>

<div class="text-center"><button type="submit" name="button" class="btn btn-primary" [disabled]="form.invalid">提交</button>

</表单>

我试图通过更新表单控件值来更新 showImage 方法中的表单.但是,我无法使用图片更新表单.当我尝试将其上传到locationPicture"和itemPicture"时,出现以下错误:

未能在HTMLInputElement"上设置value"属性:此输入元素接受一个文件名,该文件名只能以编程方式设置为空字符串.

请对此提供任何帮助

解决方案

我也遇到了这个问题,不过我们可以分别处理file和其他表单域.

这是我的代码,我想将 FormData Object 发布到 Django REST API,这个 formData 包含字符串和图像,还有 user_namepassword.我创建了一个组件 - upload-image-form

这是我要贴的,一个Image类(我自己定义的)

//images.ts导出类图像{构造函数(公共 ID:号码,public created: string,//由后端设置公共用户 ID:号码,公共文件网址:字符串,公共所有者:字符串,公共des?:字符串,公共本地图像?:文件,) { }}

这是我的组件

//upload-image-form.component.ts从'@angular/core'导入{组件,OnInit,输入};从'@angular/forms/forms' 导入 { NgForm };从'@angular/forms' 导入 { FormControl, FormGroup, FormBuilder };从'../image'导入{图像};从'../user'导入{用户};从 '../image.service' 导入 { ImageService };@零件({选择器:'app-upload-image-form',templateUrl: './upload-image-form.component.html',styleUrls: ['./upload-image-form.component.css']})导出类 UploadImageFormComponent 实现 OnInit {@Input() 用户:用户;//该值来自父组件用户详细信息的模板私人文件:文件;私有表单数据:FormData = new FormData();私有图像形式:FormGroup;私人提交=假;private imageUrl = 'http://192.168.201.211:8024/images/';私人密码:字符串;构造函数(私有图像服务:图像服务,私人 fb:FormBuilder,) { }ngOnInit() {控制台日志(this.user);this.createFrom(this.user);//在这里创建表单,这样我们就可以得到 this.user 的值}创建从(用户:用户){//我没有在这个表单中放置文件字段this.imageForm = this.fb.group({编号:1,创建:'20170825',用户 ID:用户 ID,fileUrl: 'http://images.fineartamerica.com/images-medium-large-5/mt-shuksan-picture-lake-dennis-romano.jpg',所有者:user.username,des: '',密码:'',})控制台日志(用户);}//https://stackoverflow.com/a/41465502/2803344//从表单输入中获取文件对象onChange(事件:EventTarget){让 eventObj: MSInputMethodContext = <MSInputMethodContext>事件;让目标:HTMLInputElement = eventObj.target;让文件:FileList = target.files;this.file = 文件 [0];}提交(){//分别处理字符串字段和文件this.submitted = true;控制台.log(this.file);//文件在这里,被 onChange() 捕获控制台日志(this.imageForm.value);//其他字段在这里,被formGroup捕获this.formData.append('localImage', this.file, this.file.name);for (let item in this.imageForm.value) {控制台日志(项目)如果(项目!== '密码'){this.formData.append(item, this.imageForm.value[item]);}别的 {this.password = this.imageForm.value[item];}}//console.log('###这里是整个表单数据');控制台日志(this.formData);console.log(this.formData.get('fileUrl'));console.log(this.user.username);this.imageService.post(this.formData, this.user.username, this.password).then(res =>{控制台日志(res);});}onClick(形式:FormGroup){表单.重置({用户 ID:this.user.id,所有者:this.user.username,创建:'20170825',fileUrl: 'http://www.fujifilm.com.sg/Products/digital_cameras/x/fujifilm_x_t1/sample_images/img/index/ff_x_t1_001.JPG',})this.submitted=false;控制台日志(表单值);}}

这是我的模板

<div [隐藏]="已提交" *ngIf="用户"><h2>上传新图片</h2><form [formGroup]="imageForm" (ngSubmit)="onSubmit()" ><div class="form-group"><label for="fileUrl">文件网址</label><input type="url" class="form-control" id="fileUrl"formControlName="fileUrl" required><div [hidden]="imageForm.get('fileUrl').valid || imageForm.get('fileUrl').pristine"class="警报警报-危险">文件网址为必填项

<p>{{imageForm.get('fileUrl').valid |json}}</p><p>{{imageForm.get('fileUrl').value |json}}</p>

<!-- 上传图片不要在 formGroup 中定义这个字段--><div class="form-group"><label for="localImage">本地文件</label><input type="file" class="form-control" id="localImage"(change)="onChange($event)" accept=".jpg, .png" >

<div class="form-group"><label for="des">描述</label><input type="text" class="form-control" id="des"formControlName="des">

<div class="form-group"><label for="userId">用户 ID</label><input type="text" class="form-control" id="userId"formControlName="userId" 只读><p>{{imageForm.get('userId').value |json}}</p>

<div class="form-group"><label for="owner">所有者</label><input type="text" class="form-control" id="owner"formControlName="owner" readonly>

<!-- 输入用户密码--><div class="form-group"><label for="pw">密码</label><input type="password" class="form-control" id="pw"formControlName="pw" required>

<button type="submit" class="btn btn-success" [disabled]="!imageForm.valid">提交</button></表单>

最后,这是我的图像服务

//image.service.ts从@angular/core"导入{可注射};从@angular/http"导入{标题,Http,RequestOptions};导入 'rxjs/add/operator/toPromise';从./image"导入{图像};从'./user'导入{用户};@Injectable()导出类 ImageService {private imageUrl = 'http://192.168.201.211:8024/images/';//设置授权头,https://stackoverflow.com/a/34465070/2803344createAuthorizationHeader(标题:标题,名称:字符串,密码:字符串){headers.append('授权', '基本' +btoa(`${name}:${pw}`));}创建选项(名称:字符串,密码:字符串){让标题=新标题();this.createAuthorizationHeader(headers, name, pw);//headers.append('Content-Type', 'application/json');//没有这个//headers.append('Content-Type', 'multipart/form-data');//没有这个let options = new RequestOptions({ headers: headers });退货选项;}构造函数(私有http:Http){}getImageById(id: number): Promise{const url = `${this.imageUrl}`;控制台日志(网址);让标题=新标题();让令牌 = '令牌';headers.append('X-Auth-Token', token);返回 this.http.get(url, {headers: headers}).承诺()//.then(res => res.json().data as Image).then(res => console.log(res)).catch(this.handleError);}getImageByUrl(url: string): Promise{返回 this.http.get(url).承诺().then(res => res.json() as Image)//.then(res => console.log(res)).catch(this.handleError);}post(formData: FormData, user: string, pw: string): Promise{让选项 = this.createOptions(user, pw);console.log('我们会有一个帖子!');console.log(formData.get('localImage'));console.log(formData.get('fileUrl'));console.log(formData.get('des'));返回 this.http.post(this.imageUrl, formData, options).承诺().then(res => res.json() as Image).catch(this.handleError);}private handleError(error: any): Promise{console.error('发生错误', error);//仅用于演示目的返回 Promise.reject(error.message || error);}}

你可以在github中找到整个项目,https://github.com/OnlyBelter/图像共享系统2.

I have the code below:

import { Component, OnInit, ElementRef } from '@angular/core';
import { FormArray, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'

@Component({
  selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  showSort: boolean = false;
  form: FormGroup;
  name: FormControl;
  sortSelf: FormControl;
  sortItem: FormArray;
  locationItems: FormArray;

  constructor(private _fb: FormBuilder, private _elementRef: ElementRef ) {
  }

  ngOnInit(): void {
    this.sortItem = this._fb.array([this.initSort()]);

    this.form = this._fb.group({
      sortItem: this.sortItem
    });
  }

  initSort() {
    return this._fb.group({
      locationPicture: new FormControl('', []),
      locationItems: this._fb.array([
        this.initSortItems()
      ])
    })
  }

  initSortItems() {
    return this._fb.group({
      itemPicture: new FormControl('', [])
    })
  }

  addSort() {
    this.sortItem.push(this.initSort());
  }

  addSortLocationItem(i?: number, t?: number) {
    const control: FormArray = <FormArray> this.sortItem.at(i).get('locationItems');
    control.push(this.initSortItems());
  }

  showImage(event, level?: string, i?: number, t?: number){
    let file = event.target.files[0];
    if(level === 'locationPicture'){
      (<FormArray>this.sortItem.at(i)).controls['locationPicture'].setValue(file, {onlySelf: true});
    }else{
      (<FormArray>this.sortItem.at(i).get('locationItems')).at(t).get('itemPicture').setValue(file, {onlySelf: true});
    }
  }

  next(value, valid: boolean){
    console.log(`this is value ${JSON.stringify(value, null, 4)}`);
  }
 }

Mark Up:

<div class="col-md-8 col-md-offset-2">
  <form class="" action="index.html" method="post" [formGroup]="form" (ngSubmit)="next(form.value, form.valid)">
    <div class="form-group">

      <div formArrayName="sortItem" class="">
        <div class="top-buffer-small">
          <a (click)="addSort()" style="cursor: default">
            Add Sort Location +
          </a>
        </div>
        <div *ngFor="let sortLocation of sortItem.controls; let i=index">

            <div [formGroupName]="i" class="">
              <div class="form-group">
                  <label>Location Picture</label>
                  <input type="file" formControlName="locationPicture" class="form-control locationPicture" accept="image/*" capture="camera" (change)="showImage($event, 'locationPicture', i, t)">
                  <!-- <input type="file" formControlName="locationPicture" (change)="showImage($event)" /> -->
                  <img src="" alt="" class="location-image" width="80" height="80">
                  <small class="form-text text-muted" [hidden]="sortItem.controls[i].controls.locationPicture.valid">
                      Picture is required
                  </small>
              </div>

                <div formArrayName="locationItems" class="col-md-10 col-md-offset-1">
                  <div class="row">
                    <a (click)="addSortLocationItem(i,t)" style="cursor: default">
                      Add Item +
                    </a>
                  </div>
                  <!-- <div class="from-group" *ngFor="let eachItem of form.controls.sortItem.controls[i].controls.locationItems.controls; let t=index"> -->
                  <div class="form-group" *ngFor="let eachItem of sortLocation.get('locationItems').controls; let t=index">

                      <div [formGroupName]="t">
                        <div class="form-group">
                            <label>Item Picture</label>
                            <input type="file" formControlName="itemPicture" class="form-control itemPicture" capture="camera" (change)="showImage($event, 'itemPicture', i, t)">
                            <img src="" alt="" class="item-image" width="80" height="80">
                            <small class="form-text text-muted" [hidden]="sortItem.controls[i].controls.locationItems.controls[t].controls.itemPicture.valid">
                                Picture is required
                            </small>
                         </div>
                      </div>
                    </div>
                </div>
                <div class="clearfix"></div>
            </div>
        </div>
      </div>
    </div>
    <div class="text-center">
      <button type="submit" name="button" class="btn btn-primary" [disabled]="form.invalid">Submit</button>
    </div>
  </form>
</div>

I am trying to update the form within the showImage method by updating the formcontrol values. However, I cannot get the form to update with the picture. When I try to upload it on the 'locationPicture' and 'itemPicture', I get the following error:

Failed to set the 'value' property on 'HTMLInputElement': This input element accepts a filename, which may only be programmatically set to the empty string.

Please any help with this will be great

解决方案

I also got this problem, but we can deal with file and other form field separately.

This is my code, I want to post a FormData Object to Django REST API, this formData contains both strings and image, also with user_name and password. I created a component - upload-image-form

This is what I want to post, an Image class(I define it by myself)

// images.ts
export class Image {

    constructor(
        public id: number,
        public created: string,  // set by back end
        public userId: number,
        public fileUrl: string,
        public owner: string,
        public des?: string,
        public localImage?: File,
    ) { }

}

This is my component

// upload-image-form.component.ts
import { Component, OnInit, Input } from '@angular/core';
import { NgForm } from '@angular/forms/forms';
import { FormControl, FormGroup, FormBuilder } from '@angular/forms';

import { Image } from '../image';
import { User } from '../user';
import { ImageService } from '../image.service';


@Component({
    selector: 'app-upload-image-form',
    templateUrl: './upload-image-form.component.html',
    styleUrls: ['./upload-image-form.component.css']
})
export class UploadImageFormComponent implements OnInit {

    @Input() user: User;  // this value comes from parent component user-detail's tempolate
    private file: File;
    private formData: FormData = new FormData();
    private imageForm: FormGroup;
    private submitted = false;
    private imageUrl = 'http://192.168.201.211:8024/images/';
    private password: string;

    constructor(
        private imageService: ImageService,
        private fb: FormBuilder,
    ) { }

    ngOnInit() {
        console.log(this.user);
        this.createFrom(this.user);  // create form here, so we can get this.user's value
    }

    createFrom(user: User) {
        // I didn't put file field in this form
        this.imageForm = this.fb.group({
            id: 1,
            created: '20170825',
            userId: user.id,
            fileUrl: 'http://images.fineartamerica.com/images-medium-large-5/mt-shuksan-picture-lake-dennis-romano.jpg',
            owner: user.username,
            des: '',
            pw: '',
        })
        console.log(user);
    }

    // https://stackoverflow.com/a/41465502/2803344
    // get a file object from form input
    onChange(event: EventTarget) {
        let eventObj: MSInputMethodContext = <MSInputMethodContext> event;
        let target: HTMLInputElement = <HTMLInputElement> eventObj.target;
        let files: FileList = target.files;
        this.file = files[0];
    }

    onSubmit() {
        // deal with string fields and file separately
        this.submitted = true;
        console.log(this.file);  // file is here, captured by onChange()
        console.log(this.imageForm.value);  // other fields are here, captured by formGroup

        this.formData.append('localImage', this.file, this.file.name);
        for (let item in this.imageForm.value) {
            console.log(item)
            if (item !== 'pw') {
                this.formData.append(item, this.imageForm.value[item]);
            }
            else {
                this.password = this.imageForm.value[item];
            }

        }

        // console.log('###here is the total form data');
        console.log(this.formData);
        console.log(this.formData.get('fileUrl'));
        console.log(this.user.username);
        this.imageService.post(this.formData, this.user.username, this.password)
                         .then(res =>{
                           console.log(res);
                         });
    }

    onClick(form: FormGroup) {
        form.reset({
            userId: this.user.id,
            owner: this.user.username,
            created: '20170825',
            fileUrl: 'http://www.fujifilm.com.sg/Products/digital_cameras/x/fujifilm_x_t1/sample_images/img/index/ff_x_t1_001.JPG',
        })
        this.submitted=false;
        console.log(form.value);
    }

}

This is my template

<!-- upload-image-form.component.html -->
<div [hidden]="submitted" *ngIf="user">

    <h2>Upload New Image</h2>

    <form [formGroup]="imageForm" (ngSubmit)="onSubmit()" >
        <div class="form-group">
            <label for="fileUrl">File Url</label>
            <input type="url" class="form-control" id="fileUrl" 
            formControlName="fileUrl" required>
            <div [hidden]="imageForm.get('fileUrl').valid || imageForm.get('fileUrl').pristine" 
                  class="alert alert-danger">
              File Url is required
            </div>
            <p>{{imageForm.get('fileUrl').valid | json}}</p>
            <p>{{imageForm.get('fileUrl').value | json}}</p>
        </div>
        <!-- upload an image 
        don't define this field in formGroup-->
        <div class="form-group">
            <label for="localImage">Local File</label>
            <input type="file" class="form-control" id="localImage"
            (change)="onChange($event)" accept=".jpg, .png" >
        </div>
        <div class="form-group">
            <label for="des">Description</label>
            <input type="text" class="form-control" id="des" 
            formControlName="des">
        </div>
        <div class="form-group">
            <label for="userId">User ID</label>
            <input type="text" class="form-control" id="userId" 
            formControlName="userId" readonly>
            <p>{{imageForm.get('userId').value | json}}</p>
        </div>
        <div class="form-group">
            <label for="owner">Owner</label>
            <input type="text" class="form-control" id="owner"
            formControlName="owner" readonly>
        </div>
        <!-- input user's password -->
        <div class="form-group">
            <label for="pw">password</label>
            <input type="password" class="form-control" id="pw"
            formControlName="pw" required>
        </div>
        <button type="submit" class="btn btn-success" [disabled]="!imageForm.valid">Submit</button>
    </form>
</div>

At last, this is my image service

// image.service.ts
import { Injectable } from '@angular/core';
import { Headers, Http, RequestOptions } from "@angular/http";

import 'rxjs/add/operator/toPromise';

import { Image } from "./image";
import { User } from './user';

@Injectable()
export class ImageService {

    private imageUrl = 'http://192.168.201.211:8024/images/';
    //set headers for authorization, https://stackoverflow.com/a/34465070/2803344
    createAuthorizationHeader(headers: Headers, name: string, pw: string) {
        headers.append('Authorization', 'Basic ' +
          btoa(`${name}:${pw}`)); 
    }

    createOptions(name: string, pw: string) {
        let headers = new Headers();
        this.createAuthorizationHeader(headers, name, pw);
        // headers.append('Content-Type', 'application/json');  // without this
        // headers.append('Content-Type', 'multipart/form-data');  // without this
        let options = new RequestOptions({ headers: headers });
        return options;
    }

    constructor(private http: Http) { }

    getImageById(id: number): Promise<Image> {
        const url = `${this.imageUrl}`;
        console.log(url);
        let headers = new Headers();
        let token = 'token';
        headers.append('X-Auth-Token', token);
        return this.http.get(url, {headers: headers})
                        .toPromise()
                        // .then(res => res.json().data as Image)
                        .then(res => console.log(res))
                        .catch(this.handleError);
    }

    getImageByUrl(url: string): Promise<Image> {
        return this.http.get(url)
                      .toPromise()
                      .then(res => res.json() as Image)
                      // .then(res => console.log(res))
                      .catch(this.handleError);
    }

    post(formData: FormData, user: string, pw: string): Promise<Image> {
        let options = this.createOptions(user, pw);
        console.log('we will have a post!');
        console.log(formData.get('localImage'));
        console.log(formData.get('fileUrl'));
        console.log(formData.get('des'));
        return this.http.post(this.imageUrl, formData, options)
                        .toPromise()
                        .then(res => res.json() as Image)
                        .catch(this.handleError);
    }

    private handleError(error: any): Promise<any> {
        console.error('An error occurred', error); // for demo purposes only
        return Promise.reject(error.message || error);
    }
}

You can find the whole project in github, https://github.com/OnlyBelter/image-sharing-system2.

这篇关于更新作为 Angular2 中 formArray 中的文件输入的 formControl的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆