头图

Angular 响应式表单使用显式的、不可变的方式,管理表单在特定的时间点上的状态。对表单状态的每一次变更都会返回一个新的状态,这样可以在变化时维护模型的整体性。响应式表单是围绕 Observable 流构建的,表单的输入和值都是通过这些输入值组成的流来提供的,它可以同步访问。

响应式表单通过对数据模型的同步访问提供了更多的可预测性,使用 Observable 的操作符提供了不可变性,并且通过 Observable 流提供了变化追踪功能。

要使用响应式表单控件,就要从 @angular/forms 包中导入 ReactiveFormsModule,并把它添加到你的 NgModule 的 imports 数组中。

import { ReactiveFormsModule } from '@angular/forms';

然后,生成一个新的 FormControl 实例,并把它保存在组件中。

要注册一个表单控件,就要导入 FormControl 类并创建一个 FormControl 的新实例,将其保存为类的属性。

import { Component } from '@angular/core';
import { FormControl } from '@angular/forms';

@Component({
  selector: 'app-name-editor',
  templateUrl: './name-editor.component.html',
  styleUrls: ['./name-editor.component.css']
})
export class NameEditorComponent {
  name = new FormControl('');
}

通过在你的组件类中创建这些控件,你可以直接对表单控件的状态进行监听、修改和校验。

到现在为止,我们只是在 Component 里创建了一个 FormControl 并把它赋给 Component 类的实例。但是,Component 的模板还感知不到这个 FormControl.

我们需要修改 Component 模板文件,将模板里某个控件同 Component FormControl 实例绑定起来。

<label for="name">Name: </label>
<input id="name" type="text" [formControl]="name">

绑定的语法:

[formControl]="<Component 中用来保存 formControl 的类实例>"

使用这种模板绑定语法,把该表单控件注册给了模板中名为 name 的输入元素。这样,表单控件和 DOM 元素就可以互相通讯了:视图会反映模型的变化,模型也会反映视图中的变化。
这个通信是双向的。

有时在实际开发中,我们还能看到 FormGroup 的使用例子:

Form Group 即表单组,定义了一个带有一组控件的表单,你可以把它们放在一起管理。

就像 FormControl 的实例能让你控制单个输入框所对应的控件一样,FormGroup 的实例也能跟踪一组 FormControl 实例(比如一个表单)的表单状态。当创建 FormGroup 时,其中的每个控件都会根据其名字进行跟踪。

看一个 FormGroup 创建例子:

import { Component } from '@angular/core';
import { FormGroup, FormControl } from '@angular/forms';

@Component({
  selector: 'app-profile-editor',
  templateUrl: './profile-editor.component.html',
  styleUrls: ['./profile-editor.component.css']
})
export class ProfileEditorComponent {
  profileForm = new FormGroup({
    firstName: new FormControl(''),
    lastName: new FormControl(''),
  });
}

现在,这些独立的表单控件被收集到了一个控件组中。这个 FormGroup 用对象的形式提供了它的模型值,这个值来自组中每个控件的值。 FormGroup 实例拥有和 FormControl 实例相同的属性(比如 value、untouched)和方法(比如 setValue())。

我们仍需将这个 FormGroup 实例关联到模板文件里。

这个表单组还能跟踪其中每个控件的状态及其变化,所以如果其中的某个控件的状态或值变化了,父控件也会发出一次新的状态变更或值变更事件。该控件组的模型来自它的所有成员。在定义了这个模型之后,你必须更新模板,来把该模型反映到视图中。

<form [formGroup]="profileForm">

  <label for="first-name">First Name: </label>
  <input id="first-name" type="text" formControlName="firstName">

  <label for="last-name">Last Name: </label>
  <input id="last-name" type="text" formControlName="lastName">

</form>

注意,就像 FormGroup 所包含的那控件一样,profileForm 这个 FormGroup 也通过 FormGroup 指令绑定到了 form 元素,在该模型和表单中的输入框之间创建了一个通讯层。 由 FormControlName 指令提供的 formControlName 属性把每个输入框和 FormGroup 中定义的表单控件绑定起来。这些表单控件会和相应的元素通讯,它们还把更改传给 FormGroup,这个 FormGroup 是模型值的事实之源。

当然,实际开发中有另外一种实现方法:

先创建一个空的 FormGroup,再把后续创建的 FormControl 实例,然后通过 setControl 设置到 formGroup 里。

  protected buildForm() {
    const form = new FormGroup({});
    form.setControl('product', new FormControl(null));

    this.form = form;
  }

模板文件的实现:

<form [formGroup]="form" class="quick-order-form-container">
  <div class="quick-order-form-input">
    <input
      formControlName="product"
      placeholder="{{ 'quickOrderForm.placeholder' | cxTranslate }}"
      type="text"
    />

更多Jerry的原创文章,尽在:"汪子熙":


注销
1k 声望1.6k 粉丝

invalid