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 实例绑定起来。
绑定的语法:
[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 实例关联到模板文件里。
这个表单组还能跟踪其中每个控件的状态及其变化,所以如果其中的某个控件的状态或值变化了,父控件也会发出一次新的状态变更或值变更事件。该控件组的模型来自它的所有成员。在定义了这个模型之后,你必须更新模板,来把该模型反映到视图中。
注意,就像 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;
}
模板文件的实现: