在Angular 2中使用FormArray的ControlValueAccessor

时间:2016-11-05 14:59:18

标签: forms angular

我有一个处理输入控件数组的子组件。我希望对子组件进行formcontrol。

我正在传递json对象的数组,这是将父表单绑定到子组件的正确方法,其中FormArray具有2个表单控件,首先需要使用Validator。

这是初始代码

<h1>Child</h1>
<div formArrayName="names">
 <div *ngFor="let c of names.control">
  <input formControlName="firstName">
  <input formControlName="lastName">
 </div>
</div>

意图是将父表单与子组件中的输入控件数组绑定。如果子组件中的一个输入控件没有必填字段,则表单也将变为无效。

http://plnkr.co/edit/HznCJfSEiSV28ERqNiWr?p=preview

2 个答案:

答案 0 :(得分:1)

您必须使用formArrayName指令和*ngFor,如下所示:

<form [formGroup]="form" (ngSubmit)="sayHello()">
       <input formControlName="name"><br>
       <input formControlName="email"><br>
       <div formArrayName="username">
           <div *ngFor="let user of username.controls; let i=index">
                <my-child formControlName="i"></my-child>
           </div>
       </div>
       <button type="submit">Register</button>
</form>

使用FormBuilder时,您还必须使用FormArray

form = new FormGroup({
     name: new FormControl('My Name'),
     username: new FormArray([
                  new FormControl("value"),// ControlValueAccesor is applied only to one control, not two. So you cannot use javascript object like you are using below this line.
                  {firstName:"Anna", lastName:"Smith"},
                  {firstName:"Peter", lastName:"Jones"}
                ])
   });

有关详细信息,请see this doc.

案例2:传递FormGroup:

form = new FormGroup({
     name: new FormControl('My Name'),
     username: new FormArray([
                  new FormGroup({
                        firstName: new FormControl('Anna'),
                        lastName: new FormControl('Smith')
                  }),
                  new FormGroup({
                        firstName: new FormControl('Peper'),
                        lastName: new FormControl('Jones')
                  }),
                ])
   })

如果您要将FormGroup作为ngModel参数传递,则不能!

答案 1 :(得分:0)

我喜欢解决旧帖子:)

关键是您的自定义窗体组件在FormArray内部,然后使用“ writeValue”创建formArray,请参见stackblitz

@Component({
  selector: "my-child",
  template: `
    <h1>Child</h1>

    <div *ngFor="let group of formArray.controls" [formGroup]="group">
      <input formControlName="firstName" (blur)="_onTouched()" />
      <input formControlName="lastName" (blur)="_onTouched()"/>
    </div>
  `,
  providers: [
    { provide: NG_VALUE_ACCESSOR, useExisting: Child, multi: true },
    { provide: NG_VALIDATORS, useExisting: Child, multi: true }
  ]
})
export class Child implements ControlValueAccessor {
  formArray: FormArray;
  _onChange;
  _onTouched;

  writeValue(value: any) {
    this.formArray = new FormArray(
      value.map(x => {
        return new FormGroup({
          firstName: new FormControl(x.firstName, Validators.required),
          lastName: new FormControl(x.firstName, Validators.required)
        });
      })
    );
    this.formArray.valueChanges.subscribe(res => {
      this._onChange(res);
    });
  }

  registerOnChange(fn: (value: any) => void) {
    this._onChange = fn;
  }

  registerOnTouched(fn:(value: any) => void) {
    this._onTouched=fn;
  }

  validate({ value }: FormControl) {
    return !this.formArray || this.formArray.valid
      ? null
      : { error: "Some fields are not fullfilled" };
  }
}