Angular之FormArray全探索

Posted by Kai on September 18, 2018

前提

大家都知道Angular中表单创建有两种方式
一种是 Template-Driven 模板驱动
另一种是 Reactive/Model-Driven 动态表单

还一个基础
FormControl
FormArray
FormGroup
这三者都是继承自AbstractControl这个基本class
本是同一类东西 可偏偏这个formArray不支持模板驱动的写法
官方17年2月就加入了TODO list 到现在还没解决你敢信
无奈只能用动态表单。
需要注意的是FormArray的结构需要FormGroup作为父级。下面代码中可以看到写法

如何直接把FormArray放进模板驱动的form里

上面说过 formArray 没有模板驱动方式
但我们可以把其封装成单独的组件,然后用父级form的api加入进去

import { Component, OnInit, Input } from "@angular/core";
import { FormBuilder, NgForm, FormArray, FormGroup } from "@angular/forms";

@Component({
  selector: "array-form",
  template: `
      <ng-container [formGroup]="formGroup">
        <button type="button" (click)="addItem()">add</button>
        <button type="button" (click)="removeItem()">remove</button>
        <div formArrayName="formArray" *ngFor="let item of formArray.controls; let i = index;">
            <ng-container [formGroupName]="i"><br>
                <input formControlName="name" type="text" placeholder="name"><br>
                <input formControlName="phone" type="text" placeholder="phone">
            </ng-container>
        </div>
      </ng-container><br><br><br>
    `
})
export class ArrayFormComponent implements OnInit {
  @Input() name: string;
  @Input() form: NgForm; // 把父级的form拿到 用于插入这个父级form
  formGroup: FormGroup; // formArray需要formGroup这个中间件才能循环
  formArray: FormArray;

  constructor(private formBuilder: FormBuilder) {}

  ngOnInit() {
    let array = [];
    this.formArray = this.formBuilder.array(array);
    this.formGroup = this.formBuilder.group({
      formArray: this.formArray
    });
    this.form.control.addControl(this.name, this.formArray);
    // 直接插入array层 不需要中间那层FormGroup 但你又不能抛弃formGroup 因为渲染模板需要formGroup
  }
  initItem(): FormGroup {
    const fg = this.formBuilder.group({
      name: "",
      phone: ""
    });
    return fg;
  }

  addItem() {
    const formArray = <FormArray>this.formGroup.controls["formArray"];
    formArray.push(this.initItem());
  }

  removeItem(index: number) {
    const formArray = <FormArray>this.formGroup.controls["formArray"];
    formArray.removeAt(index);
  }
}

接下来是父组件 就可以直接按模板驱动的写法

import { Component } from "@angular/core";
import { NgForm } from "@angular/forms";

@Component({
  selector: "app-root",
  template: `
    <form #detailForm="ngForm" (ngSubmit)="submit(detailForm)">
        form表单:<br>
        <input name="id" ngModel type="text" placeholder="id"><br>
        <array-form name="detail" [form]="detailForm"></array-form>
        <button type="submit">submit</button>
    </form>
  `
})
export class AppComponent {
  submit(form: NgForm) {
    const params = form.value; // 模板驱动取值就是这么简洁
    //TODO submit to api
    console.log(params);
  }
}

预览图
全部代码如下
Edit Angular之FormArray

原创文章 转载请注明出处 原文链接 https://kavil.github.io/2018/09/18/AngularFormArray/