响应式表单使用显式的、不可变的方式,管理表单在特定的时间点上的状态。对表单状态的每一次变更都会返回一个新的状态,这样可以在变化时维护模型的整体性。响应式表单是围绕 Observable 的流构建的,表单的输入和值都是通过这些输入值组成的流来提供的,它可以同步访问。
响应式表单还提供了一种更直观的测试路径,因为在请求时你可以确信这些数据是一致的、可预料的。这个流的任何一个消费者都可以安全地操纵这些数据。
响应式表单与模板驱动的表单有着显著的不同点。响应式表单通过对数据模型的同步访问提供了更多的可预测性,使用 Observable 的操作符提供了不可变性,并且通过 Observable 流提供了变化追踪功能。
合理使用Angular响应式表单,将使我们更能简单的实现一个复杂的表单
表单的两种创建方式
手动创建实例
直接使用FormGroup与FormControl创建
this.profileForm = new FormGroup({
firstName: new FormControl(''),
lastName: new FormControl(''),
address: new FormGroup({
street: new FormControl(''),
city: new FormControl(''),
state: new FormControl(''),
zip: new FormControl('')
})
});
使用表单构建器
使用FormBuilder服务创建
this.profileForm = this.fb.group({
firstName: [''],
lastName: [''],
address: this.fb.group({
street: [''],
city: [''],
state: [''],
zip: ['']
}),
});
Tips:当然,两种方式混合使用也是没问题的
优雅的使用响应式表单
合理使用 formState
、 disable
、 enable
、 registerControl
实现控件的禁用/编辑状态
虽然在Angular的类型定义中 formState
为 any
类型,但在实际的使用中,它的类型如下:
interface FormState { value: any; disabled: boolean; }
在构建表单时,若是有需要某个字段disabled,下面的方式就可以帮你实现:
this.profileForm = this.fb.group({
firstName: [{value: null, disabled: true}],
});
// 或者,两种方式都是一样的效果
this.profileForm = new FormGroup({
firstName: new FormControl({value: null, disabled: true}),
});
在表单使用中,动态enable/disable,这时候就需要借助FormGroup、FormControl实现了:
this.profileForm.disable();
this.profileForm.enable();
this.profileForm.get('firstName').disable();
this.profileForm.get('firstName').reset({value: 'Outh', disabled: false});
this.profileForm.reset({
firstName: {value: null, disabled: true},
lastName: {value: 'Jim', disabled: false},
address: {
street: null,
city: null,
state: null,
zip: null
},
});
使用 addControl
、 removeControl
、 FormArray
动态删减表单控件
使用方式如下:
this.profileForm.addControl('aliases', this.fb.array([
this.fb.control('')
]));
this.profileForm.removeControl('lastName');
const aliasesArray = (this.profileForm.get('aliases') as FormArray);
aliasesArray.push(this.fb.control(''));
aliasesArray.removeAt(1);
aliasesArray.reset();
template配合响应式表单
控件有禁用/编辑状态
<div *ngIf="profileForm.get('firstName')?.enabled">
<input formControlName="firstName" />
</div>
动态的表单控件
<div *ngIf="profileForm.get('firstName')">
<input formControlName="firstName" />
</div>
Tips:若是控件名称位置,可以使用
Object.keys
方法实现
表单数组展示
<form nz-form [formGroup]="profileForm" nzLayout="horizontal">
<div formArrayName="aliases">
<ng-container *ngFor="let g of profileForm.get('aliases')?.controls; let i= index" [formGroupName]="i">
<nz-form-item>
<nz-form-label nzFor="name" nzSpan="6" nzRequired>name</nz-form-label>
<nz-form-control nzSpan="18">
<input nz-input formControlName="name" id="name" name="name" placeholder="">
</nz-form-control>
</nz-form-item>
<nz-form-item>
<nz-form-label nzFor="image" nzSpan="6" nzRequired>image</nz-form-label>
<nz-form-control nzSpan="18">
<input nz-input formControlName="image" id="image" name="image" placeholder="">
</nz-form-control>
</nz-form-item>
</ng-container>
</div>
</form>
基于业务对象模型的元数据,动态创建表单
关于动态表单,官方文档以详细列出使用方式了,具体请看https://angular.cn/guide/dynamic-form
更多详细用法请访问响应式表单,推荐使用Angular CLI搭建本地开发环境,自行体验O_o