0%

Angular响应式表单之FormArray

前面我们了解了响应式表单的FormGroup来管理一组表单控件。但我们前面的操作都是立足于我们明确的知道表单是有哪些控件的,那假设我们并不知道会有什么控件,需要用户可以动态操作增减控件呢?响应式表单提供了FormArray来动态管理表单控件。和FormGroup不一样的是,我们不需要指定一个Key来绑定控件,我们可以动态去处理控件。

FormArray是不能独立使用的,必须包括在FormGroup指令下面,否则会报错。

假设一个场景,我们需要构造一个“常驻人口”表单。我们希望满足的需求:

  • 添加常驻人口
  • 删除常驻人口

构建FormArray实例

我们忽略其他的东西,只关注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的区域,然后才能在内部通过FormControlNameFormArray中的控件绑定关系:

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>

FormArray中套FormGroup?

上面实现的很好,但是坑爹的产品经理过来告诉你,该需求了:常住人口不能只有名字,还需要配套的手机号。

心里一万个草泥马跑过。。。。

没法子,搞呗。

首先确立下结构,我们的人员需要namephone两个字段。FormArray是管理多个表单项,那我们的一个表单项是一个FormGroup可以吧?

说干就干。

修改新增的方法:

1
2
3
4
5
6
addPeople() {
this.peoples.push(this._fb.group({
name: null,
phone: null,
}));
}

这样每次新增的时候我们是塞了一个FormGroup,里面包含namephone两个字段。

然后修改模板中的绑定:

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的组件。显示效果为:
form array


基本了解了FormArray的使用,构造动态表单非常好用。

码字辛苦,打赏个咖啡☕️可好?💘