响应式表单提供了一种模型驱动的方式来处理表单输入,其中的值会随时间而变化,从理解上来看应该是重脚本而轻模板。 FormControl,FormGroup,FormArray都适用于创建响应式表单,可以用他们统一管理form表单的状态和值。
响应式表单简介
响应式表单使用显式的、不可变的方式,管理表单在特定的时间点上的状态。对表单状态的每一次变更都会返回一个新的状态,这样可以在变化时维护模型的整体性。响应式表单是围绕 Observable 的流构建的,表单的输入和值都是通过这些输入值组成的流来提供的,它可以同步访问。
响应式表单还提供了一种更直观的测试路径,因为在请求时你可以确信这些数据是一致的、可预料的。这个流的任何一个消费者都可以安全地操纵这些数据。
响应式表单与模板驱动的表单有着显著的不同点。响应式表单通过对数据模型的同步访问提供了更多的可预测性,使用 Observable 的操作符提供了不可变性,并且通过 Observable 流提供了变化追踪功能。
他们三个都是由ReactiveFormsModule模块提供,使用前需要在相应的模块中引入依赖。
import { ReactiveFormsModule } from '@angular/forms';
@NgModule({
imports: [
// other imports ...
ReactiveFormsModule
],
})
export class AppModule { }
FormControl,FormGroup,FormArray的应用场景
FormControl用于创建单个的元素控件实例,对单个控件进行赋值,取值,添加同步或异步校验,详细参见 Angular文档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('');
// 为控件赋值
updateName() {
this.name.setValue('Nancy');
}
}
<label>
Name:
<input type="text" [formControl]="name">
</label>
<p>
Value: {{ name.value }}
</p>
FormGroup用于创建一组的元素控件,并可以对这一组控件进行整体的赋值,取值,验证等操作,还可以通过嵌套组件的方式构建层级结构的控件组,对于使用FormGroup嵌套需要用到FormGroupName指令
,其内部依赖于FormControl;详细参见Angular文档 FormGroup
有两种更新模型值的方式:
使用 setValue()
方法来为单个控件设置新值。 setValue()
方法会严格遵循表单组的结构,并整体性替换控件的值。
使用 patchValue()
方法可以用对象中所定义的任何属性为表单模型进行替换。
setValue()
方法的严格检查可以帮助你捕获复杂表单嵌套中的错误,而 patchValue()
在遇到那些错误时可能会默默的失败。
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(''),
// 创建嵌套分组组件
address: new FormGroup({
street: new FormControl(''),
city: new FormControl(''),
state: new FormControl(''),
zip: new FormControl('')
})
});
updateProfile() {
this.profileForm.patchValue({
firstName: 'Nancy',
address: {
street: '123 Drew Street'
}
});
}
onSubmit() {
console.warn(this.profileForm.value);
}
}
<form [formGroup]="profileForm" (ngSubmit)="onSubmit()">
<label>
First Name:
<input type="text" formControlName="firstName">
</label>
<label>
Last Name:
<input type="text" formControlName="lastName">
</label>
<!-- 嵌套分组组件的应用 -->
<div formGroupName="address">
<h3>Address</h3>
<label>
Street:
<input type="text" formControlName="street">
</label>
<label>
City:
<input type="text" formControlName="city">
</label>
<label>
State:
<input type="text" formControlName="state">
</label>
<label>
Zip Code:
<input type="text" formControlName="zip">
</label>
</div>
<p>
<button (click)="updateProfile()">Update Profile</button>
</p>
<button type="submit" [disabled]="!profileForm.valid">Submit</button>
</form>
FormBuilder提供一种相对简单的方式用来创建FormControl和FormGroup以及FormArray;详细参见Angular文档 FormBuilder
手动创建多个表单控件实例会非常繁琐。FormBuilder
服务提供了一些便捷方法来生成表单控件。FormBuilder
在幕后也使用同样的方式来创建和返回这些实例,只是用起来更简单。
FormBuilder
服务有三个方法:control()
、group()
和 array()
。这些方法都是工厂方法,用于在组件类中分别生成 FormControl
、FormGroup
和 FormArray
。
通过使用FormBuilder可以将上面的 FormGroup方式创建的组件简化成下方的样式,以此减少一些重复代码;
import { Component } from '@angular/core';
import { FormBuilder } from '@angular/forms';
import { Validators } from '@angular/forms';
@Component({
selector: 'app-profile-editor',
templateUrl: './profile-editor.component.html',
styleUrls: ['./profile-editor.component.css']
})
export class ProfileEditorComponent {
profileForm = this.fb.group({
firstName: ['', Validators.required],
lastName: [''],
address: this.fb.group({
street: [''],
city: [''],
state: [''],
zip: ['']
}),
});
constructor(private fb: FormBuilder) { }
}
FormArray,基于此管理表单或列表的动态组件列表,虽然没有试过但看其模式应该是可以用来做动态表格,或者div块的内容的验证和管理;用到的指令formArrayName 详细参见Angular文档 FormArray
profileForm = this.fb.group({
firstName: ['', Validators.required],
lastName: [''],
address: this.fb.group({
street: [''],
city: [''],
state: [''],
zip: ['']
}),
aliases: this.fb.array([
this.fb.control(''),
this.fb.control('')
])
});
可以通过添加getter取值方法来代替操控FormArray对象句柄时的长语句,以达到优化代码的目的.
get aliases() {
return this.profileForm.get('aliases') as FormArray;
}
addAlias() {
this.aliases.push(this.fb.control(''));
}
<div formArrayName="aliases">
<h3>Aliases</h3> <button (click)="addAlias()">Add Alias</button>
<div *ngFor="let alias of aliases.controls; let i=index">
<!-- The repeated alias template -->
<label>
Alias:
<input type="text" [formControlName]="i">
</label>
</div>
</div>
以上