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

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

问题描述

我有以下代码:
$ b

 从'@ angular / core'导入{Component,OnInit,ElementRef}; 
从'@ angular / forms'导入{FormArray,FormBuilder,FormControl,FormGroup,Validators}
$ b @Component({
selector:'app-root',
templateUrl:'./app.component.html',
styleUrls:['./app.component.css']
})
导出类AppComponent实现OnInit {
showSort:boolean = false;
form:FormGroup;
名称:FormControl;
sortSelf:FormControl;
sortItem:FormArray;
locationItems:FormArray;

构造函数(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(){
返回this._fb.group({
itemPicture:new FormControl('',[])
})
}

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

addSortLocationItem(i ?: number,t ?: number){
const control:FormArray =< FormArray> this.sortItem.at(ⅰ)获得( locationItems’);
control.push(this.initSortItems());

$ b $ 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} ); (t).get('itemPicture')。setValue(file,{
} else {
(< FormArray> this.sortItem.at(i).get('locationItems'))。 onlySelf:true});



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


$ / code $ / pre
$ b $ p

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

< div formArrayName =sortItemclass =>
< div class =top-buffer-small>
< a(click)=addSort()style =cursor:default>
添加排序位置+
< / a>
< / div>
< div * ngFor =let sortLocation of sortItem.controls; let i = index>

< div [formGroupName] =iclass =>
< div class =form-group>
< label>位置图片< / label>
< input type =fileformControlName =locationPictureclass =form-control locationPictureaccept =image / *capture =camera(change)=showImage($ event,'locationPicture' ,i,t)>
<! - < input type =fileformControlName =locationPicture(change)=showImage($ event)/> - >
< img src =alt =class =location-imagewidth =80height =80>
图片为必填项
< / div>

< div formArrayName =locationItemsclass =col-md-10 col-md-offset-1>
< div class =row>
< a(click)=addSortLocationItem(i,t)style =cursor:default>
添加商品+
< / a>
< / div>
<! - < div class =from-group* ngFor =let each.tem 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 =fileformControlName =itemPictureclass =form-control itemPicturecapture =camera(change)=showImage($ event,'itemPicture',i,t)> ;
< img src =alt =class =item-imagewidth =80height =80>
图片为必填项
< / div>
< / div>
< / div>
< / div>
< div class =clearfix>< / div>
< / div>
< / div>
< / div>
< / div>
< div class =text-center>
< button type =submitname =buttonclass =btn btn-primary[disabled] =form.invalid> Submit< / button>
< / div>
< / form>
< / div>

我试图通过更新formcontrol值来更新showImage方法中的表单。但是,我无法获得用于更新图片的表单。当我尝试上传到'locationPicture'和'itemPicture'时,出现以下错误:

 无法设置HTMLInputElement上的'value'属性:该输入元素接受一个文件名,该文件名只能通过编程方式设置为空字符串。 

任何帮助都会很棒

file 和其他表单域。

这是我的代码,我想发布一个 FormData对象到Django REST API,这个 formData 同时包含字符串和图片,同时包含 user_name 密码。我创建了一个组件 - upload-image-form



这是我想发布的内容, Image class(我自己定义)



  // images.ts 
export class Image {

构造函数(
public id:number,
public created:string,//由后端设置
public userId:number,
public fileUrl:string,
public owner:string,
public des ?: string,
public localImage ?: File,
){}


$ / code $ / pre

这是我的组件



<$ p @ p> // upload-image-form.component.ts
从'@ angular / core'导入{Component,OnInit,Input};
从'@ angular / forms / forms'导入{NgForm};
从'@ angular / forms'导入{FormControl,FormGroup,FormBuilder};

从'../image'导入{Image};
从'../user'导入{User};
从'../image.service'中导入{ImageService};


@Component({
selector:'app-upload-image-form',
templateUrl:'./upload-image-form.component.html ',
styleUrls:['./upload-image-form.component.css']
})
导出类UploadImageFormComponent实现OnInit {

@Input( )用户:用户; //这个值来自父组件user-detail的tempolate
私有文件:File;
private formData:FormData = new FormData();
private imageForm:FormGroup;
private submitted = false;
private imageUrl ='http://192.168.201.211:8024/images/';
私人密码:字符串;

构造函数(
private imageService:ImageService,
private fb:FormBuilder,
){}

ngOnInit(){
console.log(this.user);
this.createFrom(this.user); //在这里创建表单,所以我们可以得到this.user的值
}

createFrom(user:User){
//我没有在这个表单中放置文件字段
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',
所有者:user.username,
des:' ',
pw:'',
})
console.log(user);


// https://stackoverflow.com/a/41465502/2803344
//从表单输入获取文件对象
onChange(event:EventTarget ){
let eventObj:MSInputMethodContext =< MSInputMethodContext>事件;
let target:HTMLInputElement =< HTMLInputElement> eventObj.target;
让文件:FileList = target.files;
this.file = files [0];


onSubmit(){
//分别处理字符串字段和文件
this.submitted = true;
console.log(this.file); //文件在这里,由onChange()捕获
console.log(this.imageForm.value); //其他字段在这里,由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('###这里是整个表单数据');
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);
}

}



这是我的模板



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

< h2>上载新图片< / h2>

< form [formGroup] =imageForm(ngSubmit)=onSubmit()>
< div class =form-group>
< label for =fileUrl>档案网址< / label>
< input type =urlclass =form-controlid =fileUrl
formControlName =fileUrlrequired>
< div [hidden] =imageForm.get('fileUrl')。valid || imageForm.get('fileUrl')。pristine
class =alert alert-danger>
档案URL必须为
< / div>
< p> {{imageForm.get('fileUrl')。valid | JSON}}< / p为H.
< p> {{imageForm.get('fileUrl')。value | JSON}}< / p为H.
< / div>
<! - 上传图片
不在formGroup中定义此字段 - >
< div class =form-group>
< label for =localImage>本地文件< / label>
< input type =fileclass =form-controlid =localImage
(change)=onChange($ event)accept =。jpg,.png>
< / div>
< div class =form-group>
< label for =des>描述< / label>
< input type =textclass =form-controlid =des
formControlName =des>
< / div>
< div class =form-group>
< label for =userId>用户ID< / label>
< input type =textclass =form-controlid =userId
formControlName =userIdreadonly>
< p> {{imageForm.get('userId')。value | JSON}}< / p为H.
< / div>
< div class =form-group>
< label for =owner>所有者< / label>
< input type =textclass =form-controlid =owner
formControlName =ownerreadonly>
< / div>
<! - 输入用户密码 - >
< div class =form-group>
< label for =pw>密码< / label>
< input type =passwordclass =form-controlid =pw
formControlName =pwrequired>
< / div>
< button type =submitclass =btn btn-success[disabled] =!imageForm.valid>提交< / button>
< / form>
< / div>



最后,这是我的图片服务



  // image.service.ts 
从'@ angular / core'导入{Injectable};
从@ angular / http导入{Headers,Http,RequestOptions};

导入'rxjs / add / operator / toPromise';

从./image中导入{Image};
从'./user'导入{User};

@Injectable()
导出类ImageService {

private imageUrl ='http://192.168.201.211:8024/images/';
//为授权设置标头,https://stackoverflow.com/a/34465070/2803344
createAuthorizationHeader(标题:标题,名称:字符串,pw:字符串){
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'); //没有这个
// headers.append('Content-Type','multipart / form-data'); //没有这个
let options = new RequestOptions({headers:headers});
返回选项;
}

构造函数(private http:Http){}

getImageById(id:number):Promise< Image> {
const url =`$ {this.imageUrl}`;
console.log(url);
let headers = new Headers();
让令牌='令牌';
headers.append('X-Auth-Token',令牌);
返回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> {
返回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('我们将有一个帖子!');
console.log(formData.get('localImage'));
console.log(formData.get('fileUrl'));
console.log(formData.get('des'));
返回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('发生错误,错误); //仅用于演示目的
返回Promise.reject(error.message || error);


$ / code $ / pre

您可以在github中找到整个项目 https://github.com/OnlyBelter/image-sharing-system2


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天全站免登陆