在角度6之前,我使用[(ngModel)]
将表单字段直接绑定到模型。现在不推荐使用(不能用于反应式表单),而且我不确定如何用表单值更新模型。我可以使用form.getRawValue()
,但是这需要我用新的rawValue替换当前模型-这是不利的,因为我的主模型比本地表单模型更大并且具有更多的字段。
有什么想法吗?
答案 0 :(得分:7)
如Angular Documentation中更详尽地说明的那样,对于反应式表单,您不会将表单直接绑定到您的模型。而是,您使用FormBuilder构建一个FormGroup对象(本质上是“表单”),该对象将维护其自己的模型。 在构建过程中,您将有机会以表单的形式设置初始值,通常可以通过您的模型进行设置。
然后将模板中的表单控件绑定到表单的模型。 用户与表单控件的交互将更新表单的模型。
当您准备对表单数据进行某些操作(例如“提交”表单)时, 您可以使用FormGroup的value属性或getRawValue()方法从表单字段中获取值-这两种行为不同,请参阅文档以获取详细信息。
一旦您从表单中获取值,就可以使用表单中的值更新您的模型。
答案 1 :(得分:4)
如果要绑定到文本输入之类的表单控件,请像使用其他任何反应形式一样使用此语法:
<ng-container [formGroup]="this.myFormGroup">
<input type="text" formControlName="field1">
<input type="text" formControlName="field2">
<ng-container formGroupName="subgroupName">
<input type="text" formControlName="subfield2">
</ng-container>
</ng-container>
在组件类的constructor()
中(应在模板呈现之前),使用以下语法来构建一个表单组以与该表单进行对话:
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
...
constructor(private formBuilder: FormBuilder) {
this.myFormGroup = this.formBuilder.group({
field1: [],
field2: [],
subgroupName: this.formBuilder.group({
subfield2: [],
}),
});
this.retrieveData();
}
如果您的组件需要在加载时从服务中检索数据,则必须确保它在构建表单后开始传输,然后使用patchValue()
将对象中的数据放入{{ 1}}:
FormGroup
与 private retrieveData(): void {
this.dataService.getData()
.subscribe((res: SomeDataStructure) => {
this.myFormGroup.patchValue(res);
});
}
模型的只读数据绑定的访问有所不同:
FormGroup
所有这些技术消除了对任何{{ this.myFormGroup.get('field1').value }}
{{ this.myFormGroup.get('subgroupName.subfield2').value }}
绑定的需求。
答案 2 :(得分:1)
您可以订阅表单组中的更改,并使用它来更新模型。但这不是安全的。因为您必须确保表单字段与模型字段匹配,或者添加验证模型中的字段存在。
bindModelToForm(model: any, form: FormGroup) {
const keys = Object.keys(form.controls);
keys.forEach(key => {
form.controls[key].valueChanges.subscribe(
(newValue) => {
model[key] = newValue;
}
)
});
}
我提供的服务的完整代码:
referenceFields -表示如果您有student: { name, group }
之类的复杂字段,其中 group 是引用的模型,并且您只能从该模型中获取ID:< / p>
import { Injectable } from '@angular/core';
import { FormGroup } from "@angular/forms";
@Injectable({
providedIn: 'root'
})
export class FormService {
constructor() {
}
bindModelToForm(model: any, form: FormGroup, referenceFields: string[] = []) {
if (!this.checkFieldsMatching(model, form)) {
throw new Error('FormService -> bindModelToForm: Model and Form fields is not matching');
}
this.initForm(model, form);
const formKeys = Object.keys(form.controls);
formKeys.forEach(key => {
if (referenceFields.includes(key)) {
form.controls[key].valueChanges.subscribe(
(newValue) => {
model[key] = newValue.id;
}
)
} else {
form.controls[key].valueChanges.subscribe(
(newValue) => {
model[key] = newValue;
}
)
}
});
}
private initForm(model: any, form: FormGroup) {
const keys = Object.keys(form.controls);
keys.forEach(key => {
form.controls[key].setValue(model[key]);
});
}
private checkFieldsMatching(model: any, form: FormGroup): boolean {
const formKeys = Object.keys(form.controls);
const modelKeys = Object.keys(model);
formKeys.forEach(formKey => {
if (!modelKeys.includes(formKey)) {
return false;
}
});
return true;
}
}