首先,有三种类型的表单 - FormControl
、FormGroup
和FormArray
- 都继承自AbstractControl
。
当您使用响应式表单进行验证并在组件模板中包括formGroupName
、formControlName
或formArrayName
时,实际上您在声明性地定义表单控件树与根FormGroup
模型之间的映射关系。
例如,给定以下模板:
<div [formGroup]="formGroup">
<div formGroupName="personalInfo">
First Name: <input type="text" formControlName="firstName"><br />
Last Name: <input type="text" formControlName="lastName"><br />
</div>
<div formArrayName="cities">
Top cities: <input *ngFor="let city of cities; index as i" type="text" [formControlName]="i">
</div>
</div>
您正在声明性地设置一个表单映射来收集信息,最终将产生一个特定格式的JSON对象。例如,给定上述表单模型,formGroup.value
将返回:
{
"personalInfo": {
"firstName: 'John',
"lastName: 'Smith'
},
"cities": [
"New York",
"Winnipeg",
"Toronto"
]
}
在你的模板中声明表单组的结构后,你需要在组件类中通过编程方式创建相应的 formGroup
、formControl
和 formArray
。在设置每个表单时,你可以设置其他参数:
1. Initial Form Value
2. Array of synchronous validators
3. Array of asynchronous validators
这适用于任何抽象控件。
根据上述模板,对应的formGroup模型将如下所示:
export class AppComponent {
firstName: string,
lastName: string;
cities: string[];
@Input() formGroup: FormGroup;
constructor(private fb: FormBuilder) {
this.cities = ['New York', 'Winnipeg', 'Toronto'];
this.firstName = 'John';
this.lastName = 'Smith';
this.formGroup = fb.group({
firstName: [this.firstName, Validators.required],
lastName: [this.lastName, Validators.required],
cities: fb.array(this.cities.map(t=> fb.control(t, Validators.required)))
})
}
}
要绑定到表单的任何验证标志,您可以使用根formGroup
和路径字符串(支持点)来查找特定的组、控件或数组。
例如:
<div *ngIf="formGroup.get('firstName').errors.required">First Name is Required</div>
希望这可以清楚明白。
[编辑]
更好的做法是,由于反应式表单完全是在模板中声明性地设置模型,并在组件类中以命令方式映射相同的模型,因此您应该考虑定义一个JSON模型并使用它。
例如,假设我们有一个自定义模型MyModel,其中具有firstName属性、lastName属性和cities属性。组件类应如下所示:
export class AppComponent {
@Input() model: MyModel;
@Output() modelChange: EventEmitter<MyModel>;
@Input() formGroup: FormGroup;
constructor(private fb: FormBuilder) {
this.model = new EventEmitter<MyModel>();
this.formGroup = fb.group({
firstName: [this.model.firstName, Validators.required],
lastName: [this.model.lastName, Validators.required],
cities: fb.array(this.model.cities.map(t=> fb.control(t, Validators.required)))
});
}
onSubmit() {
if (this.formGroup.valid) {
this.model = this.formGroup.value;
this.modelChange.next(this.model);
}
}
}