响应式表单使用显式的、不可变的方式,管理表单在特定的时间点上的状态。对表单状态的每一次变更都会返回一个新的状态,这样可以在变化时维护模型的整体性。响应式表单是围绕 Observable 的流构建的,表单的输入和值都是通过这些输入值组成的流来提供的,它可以同步访问。
响应式表单还提供了一种更直观的测试路径,因为在请求时你可以确信这些数据是一致的、可预料的。这个流的任何一个消费者都可以安全地操纵这些数据。
响应式表单与模板驱动的表单有着显著的不同点。响应式表单通过对数据模型的同步访问提供了更多的可预测性,使用 Observable 的操作符提供了不可变性,并且通过 Observable 流提供了变化追踪功能。

合理使用Angular响应式表单,将使我们更能简单的实现一个复杂的表单

表单的两种创建方式

手动创建实例

直接使用FormGroupFormControl创建

  1. this.profileForm = new FormGroup({
  2. firstName: new FormControl(''),
  3. lastName: new FormControl(''),
  4. address: new FormGroup({
  5. street: new FormControl(''),
  6. city: new FormControl(''),
  7. state: new FormControl(''),
  8. zip: new FormControl('')
  9. })
  10. });

使用表单构建器

使用FormBuilder服务创建

  1. this.profileForm = this.fb.group({
  2. firstName: [''],
  3. lastName: [''],
  4. address: this.fb.group({
  5. street: [''],
  6. city: [''],
  7. state: [''],
  8. zip: ['']
  9. }),
  10. });

Tips:当然,两种方式混合使用也是没问题的

优雅的使用响应式表单

合理使用 formStatedisableenableregisterControl 实现控件的禁用/编辑状态

虽然在Angular的类型定义中 formStateany 类型,但在实际的使用中,它的类型如下:

  1. interface FormState { value: any; disabled: boolean; }

在构建表单时,若是有需要某个字段disabled,下面的方式就可以帮你实现:

  1. this.profileForm = this.fb.group({
  2. firstName: [{value: null, disabled: true}],
  3. });
  4. // 或者,两种方式都是一样的效果
  5. this.profileForm = new FormGroup({
  6. firstName: new FormControl({value: null, disabled: true}),
  7. });

在表单使用中,动态enable/disable,这时候就需要借助FormGroupFormControl实现了:

  1. this.profileForm.disable();
  2. this.profileForm.enable();
  3. this.profileForm.get('firstName').disable();
  4. this.profileForm.get('firstName').reset({value: 'Outh', disabled: false});
  5. this.profileForm.reset({
  6. firstName: {value: null, disabled: true},
  7. lastName: {value: 'Jim', disabled: false},
  8. address: {
  9. street: null,
  10. city: null,
  11. state: null,
  12. zip: null
  13. },
  14. });

使用 addControlremoveControlFormArray 动态删减表单控件

使用方式如下:

  1. this.profileForm.addControl('aliases', this.fb.array([
  2. this.fb.control('')
  3. ]));
  4. this.profileForm.removeControl('lastName');
  5. const aliasesArray = (this.profileForm.get('aliases') as FormArray);
  6. aliasesArray.push(this.fb.control(''));
  7. aliasesArray.removeAt(1);
  8. aliasesArray.reset();

template配合响应式表单

控件有禁用/编辑状态

  1. <div *ngIf="profileForm.get('firstName')?.enabled">
  2. <input formControlName="firstName" />
  3. </div>

动态的表单控件

  1. <div *ngIf="profileForm.get('firstName')">
  2. <input formControlName="firstName" />
  3. </div>

Tips:若是控件名称位置,可以使用 Object.keys 方法实现

表单数组展示

  1. <form nz-form [formGroup]="profileForm" nzLayout="horizontal">
  2. <div formArrayName="aliases">
  3. <ng-container *ngFor="let g of profileForm.get('aliases')?.controls; let i= index" [formGroupName]="i">
  4. <nz-form-item>
  5. <nz-form-label nzFor="name" nzSpan="6" nzRequired>name</nz-form-label>
  6. <nz-form-control nzSpan="18">
  7. <input nz-input formControlName="name" id="name" name="name" placeholder="">
  8. </nz-form-control>
  9. </nz-form-item>
  10. <nz-form-item>
  11. <nz-form-label nzFor="image" nzSpan="6" nzRequired>image</nz-form-label>
  12. <nz-form-control nzSpan="18">
  13. <input nz-input formControlName="image" id="image" name="image" placeholder="">
  14. </nz-form-control>
  15. </nz-form-item>
  16. </ng-container>
  17. </div>
  18. </form>

基于业务对象模型的元数据,动态创建表单

关于动态表单,官方文档以详细列出使用方式了,具体请看https://angular.cn/guide/dynamic-form


更多详细用法请访问响应式表单,推荐使用Angular CLI搭建本地开发环境,自行体验O_o