Angular 2.如何在Reactive Forms中使用控件对象数组

use*_*173 13 forms angular

我需要动态创建textarea表单.我有以下模型:

this.fields = {
      isRequired: true,
      type: {
        options: [
          {
            label: 'Option 1',
            value: '1'
          },
          {
            label: 'Option 2',
            value: '2'
          }
        ]
      }
    };
Run Code Online (Sandbox Code Playgroud)

形式:

this.userForm = this.fb.group({
      isRequired: [this.fields.isRequired, Validators.required],
      //... here a lot of other controls
      type: this.fb.group({
         options: this.fb.array(this.fields.type.options),
      })
});
Run Code Online (Sandbox Code Playgroud)

模板的一部分:

<div formGroupName="type">
       <div formArrayName="options">
         <div *ngFor="let option of userForm.controls.type.controls.options.controls; let i=index">
            <textarea [formControlName]="i"></textarea>
         </div>
      </div>
</div>
Run Code Online (Sandbox Code Playgroud)

所以,你可以看到我有一些对象,我想使用label属性来显示它textarea.现在我明白了[object Object].如果我options改为简单的字符串数组,如:['Option 1', 'Option 2'],那么一切正常.但我需要使用对象.所以,而不是:

<textarea [formControlName]="i"></textarea>
Run Code Online (Sandbox Code Playgroud)

我试过了:

<textarea [formControlName]="option[i].label"></textarea>
Run Code Online (Sandbox Code Playgroud)

但是,它不起作用.
我如何使用对象数组?

这是普兰克

AJT*_*T82 25

您需要添加一个FormGroup,其中包含您的labelvalue.这也意味着表单创建的对象与您的fields对象具有相同的构建.

ngOnInit() {
  // build form
  this.userForm = this.fb.group({
    type: this.fb.group({
      options: this.fb.array([]) // create empty form array   
    })
  });

  // patch the values from your object
  this.patch();
}
Run Code Online (Sandbox Code Playgroud)

之后,我们使用OnInit中调用的方法修补值:

patch() {
  const control = <FormArray>this.userForm.get('type.options');
  this.fields.type.options.forEach(x => {
    control.push(this.patchValues(x.label, x.value))
  });
}

// assign the values
patchValues(label, value) {
  return this.fb.group({
    label: [label],
    value: [value]
  })    
}
Run Code Online (Sandbox Code Playgroud)

最后,这是一个

演示


rmc*_*rry 11

AJT_82的答案对我来说非常有用,我想我会分享如何重用他的代码并构建一个类似的例子 - 一个可能有一个更常见的用例,它邀请几个人立刻注册.像这样: 形成截图

我认为这可能有助于其他人,所以这就是我在这里添加它的原因.

您可以看到表单是电子邮件的简单文本输入数组,每个表单都加载了自定义验证程序.您可以在屏幕截图中看到JSON结构 - 请参阅模板中的前一行(感谢AJT),这是一个非常有用的想法,同时开发以查看您的模型和控件是否已连线!

首先,声明我们需要的对象.请注意,3个空字符串是模型数据(我们将绑定到文本输入):

  public form: FormGroup;
  private control: FormArray;
  private emailsModel = { emails: ['','','']} // the model, ready to hold the emails
  private fb : FormBuilder;
Run Code Online (Sandbox Code Playgroud)

构造函数是干净的(为了更容易测试,只需注入我的userService以在提交后发送表单数据):

  constructor(
    private _userService: UserService,
  ) {}
Run Code Online (Sandbox Code Playgroud)

表单是在init方法中构建的,包括存储对emailsArray控件本身的引用,以便我们稍后检查其子项(实际输入)是否被触摸,如果是,它们是否有错误:

  ngOnInit() {
    this.fb = new FormBuilder;
    this.form = this.fb.group({
      emailsArray: this.fb.array([])
    });
    this.control = <FormArray>this.form.controls['emailsArray'];
    this.patch();    
  }

  private patch(): void {
    // iterate the object model and extra values, binding them to the controls
    this.emailsModel.emails.forEach((item) => {
      this.control.push(this.patchValues(item));
    })
  }
Run Code Online (Sandbox Code Playgroud)

这是使用验证器构建每个输入控件(类型为AbstracControl):

  private patchValues(item): AbstractControl {
    return this.fb.group({
      email: [item, Validators.compose([emailValidator])] 
    })
  }
Run Code Online (Sandbox Code Playgroud)

检查输入是否被触摸以及验证器是否引发错误的2个辅助方法(请参阅模板以了解它们的使用方法 - 请注意我从*ngFor模板中传递数组的索引值):

  private hasError(i):boolean {
    // const control = <FormArray>this.form.controls['emailsArray'];
    return this.control.controls[i].get('email').hasError('invalidEmail');
  }
  private isTouched(i):boolean {
    // const control = <FormArray>this.form.controls['emailsArray'];
    return this.control.controls[i].get('email').touched;
  }
Run Code Online (Sandbox Code Playgroud)

这是验证器:

export function emailValidator(control: FormControl): { [key: string]: any } {
    var emailRegexp = /[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,3}$/;
    if (control.value && !emailRegexp.test(control.value)) {
        return { invalidEmail: true };
    }
}
Run Code Online (Sandbox Code Playgroud)

和模板:

<form [formGroup]="form" (ngSubmit)="onSubmit(form.value)" class="text-left">
    <div formArrayName="emailsArray">
        <div *ngFor="let child of form.controls.emailsArray.controls; let i=index">
            <div class="form-group" formGroupName="{{i}}">
                <input formControlName="email" 
                       class="form-control checking-field" 
                       placeholder="Email" type="text">
                <span class="help-block" *ngIf="isTouched(i)">
                    <span class="text-danger" 
                          *ngIf="hasError(i)">Invalid email address
                    </span>
                </span>
            </div>                   
        </div>
    </div>
    <pre>{{form.value | json }}</pre>            
    <div class="form-group text-center">
      <button class="btn btn-main btn-block" type="submit">INVITE</button>
    </div>
</form>
Run Code Online (Sandbox Code Playgroud)

对于它的价值,我已经开始了这个可怕的混乱 - 但是如果你看下面的代码,你可能更容易理解上面的代码!

  public form: FormGroup;
  public email1: AbstractControl;
  public email2: AbstractControl;
  public email3: AbstractControl;
  public email4: AbstractControl;
  public email5: AbstractControl;

  constructor(
    fb: FormBuilder
  ) { 
       this.form = fb.group({
      'email1': ['', Validators.compose([emailValidator])],
      'email2': ['', Validators.compose([emailValidator])],
      'email3': ['', Validators.compose([emailValidator])],
      'email4': ['', Validators.compose([emailValidator])],
      'email5': ['', Validators.compose([emailValidator])],
        });
    this.email1 = this.form.controls['email1'];
    this.email2 = this.form.controls['email2'];
    this.email3 = this.form.controls['email3'];
    this.email4 = this.form.controls['email4'];
    this.email5 = this.form.controls['email5'];
  }
Run Code Online (Sandbox Code Playgroud)

以上在模板中使用了这些div中的5个 - 不是很干!

<div class="form-group">
    <input [formControl]="email1" class="form-control checking-field" placeholder="Email" type="text"> 
    <span class="help-block" *ngIf="form.get('email1').touched">
        <span class="text-danger" *ngIf="form.get('email1').hasError('invalidEmail')">Invalid email address</span>
    </span> 
</div>
Run Code Online (Sandbox Code Playgroud)