前面我们了解了响应式表单的FormGroup
来管理一组表单控件。但我们前面的操作都是立足于我们明确的知道表单是有哪些控件的,那假设我们并不知道会有什么控件,需要用户可以动态操作增减控件呢?响应式表单提供了FormArray
来动态管理表单控件。和FormGroup
不一样的是,我们不需要指定一个Key来绑定控件,我们可以动态去处理控件。
FormArray
是不能独立使用的,必须包括在FormGroup
指令下面,否则会报错。
假设一个场景,我们需要构造一个“常驻人口”表单。我们希望满足的需求:
我们忽略其他的东西,只关注FormArray
,在组件类中创建一个表单的实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import {Component , OnInit } from '@angular/core' ;import {FormArray , FormBuilder , FormGroup } from "@angular/forms" ;@Component ({ selector : 'app-index' , templateUrl : './index.component.html' , styleUrls : ['./index.component.scss' ] }) export class IndexComponent implements OnInit { form : FormGroup ; constructor ( private _fb: FormBuilder, ) { } ngOnInit (): void { this .form = this ._fb .group ({ peoples : this ._fb .array ([]) }) } }
为了快速、方便的访问FormArray
,我们来写个get
函数:
1 2 3 get peoples (): FormArray { return this .form .get ('peoples' ) as FormArray ; }
然后在模板中使用,我们首先需要formArrayName
指令来标记个FormArray
的区域,然后才能在内部通过FormControlName
和FormArray
中的控件绑定关系:
1 2 3 4 5 6 7 8 9 <form [formGroup ]="form" > <h3 > 常住人口登记</h3 > <div formArrayName ="peoples" > <div *ngFor ="let control of peoples.controls; let i = index" > <label > 人员</label > <input type ="text" [formControlName ]="i" /> </div > </div > </form >
FormArray
实例的controls
提供了子控件的数组,我们可以通过ngFor
来遍历。由于FormArray
中的控件是匿名的,所以我们只能通过索引来进行访问。
新增、删除子控件 新增 FormArray
提供了push
方法来增加一个控件:
1 2 3 addPeople ( ) { this .peoples .push (this ._fb .control (null )); }
和模板绑定:
1 <button (click )="addPeople()" > 添加常驻人口</button >
删除 FormArray
提供了removeAt
方法来移除一个控件:
1 2 3 deletePeople (i: number ) { this .peoples .removeAt (i); }
和模板绑定:
1 2 3 4 5 <div *ngFor ="let control of peoples.controls; let i = index" > <label > 人员</label > <input type ="text" [formControlName ]="i" /> <button (click )="deletePeople(i)" > 删除</button > </div >
上面实现的很好,但是坑爹的产品经理过来告诉你,该需求了:常住人口不能只有名字,还需要配套的手机号。
心里一万个草泥马跑过。。。。
没法子,搞呗。
首先确立下结构,我们的人员需要name
和phone
两个字段。FormArray
是管理多个表单项,那我们的一个表单项是一个FormGroup
可以吧?
说干就干。
修改新增的方法:
1 2 3 4 5 6 addPeople ( ) { this .peoples .push (this ._fb .group ({ name : null , phone : null , })); }
这样每次新增的时候我们是塞了一个FormGroup
,里面包含name
和phone
两个字段。
然后修改模板中的绑定:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <form [formGroup ]="form" > <h3 > 常住人口登记</h3 > <button (click )="addPeople()" > 添加常驻人口</button > <div formArrayName ="peoples" > <div *ngFor ="let control of peoples.controls; let i = index" > <ng-container [formGroupName ]="i" > <mat-form-field > <mat-label > 姓名</mat-label > <input matInput formControlName ="name" placeholder ="请输入姓名" /> </mat-form-field > <mat-form-field > <mat-label > 手机</mat-label > <input matInput formControlName ="phone" placeholder ="请输入手机号" /> </mat-form-field > </ng-container > <button (click )="deletePeople(i)" > 删除</button > </div > </div > <button (click )="submit()" > submit</button > </form >
这里为了好看,使用了Material UI
的组件。显示效果为:
基本了解了FormArray
的使用,构造动态表单非常好用。