角度 4 将包含其他对象的对象传递给 FormBuilder.group 函数会导致奇怪的表单行为
Posted
技术标签:
【中文标题】角度 4 将包含其他对象的对象传递给 FormBuilder.group 函数会导致奇怪的表单行为【英文标题】:angular 4 passing an object containing other objects into FormBuilder.group function leads to a strange form behavior 【发布时间】:2018-01-21 18:12:36 【问题描述】:创建由以下“嵌套对象”(建筑物)组成的嵌套表单:
export class Building
id: number = 0;
doorsCount: number = 0;
description: string = '';
address: Address = new Address();
buildingType: BuildingType = new BuildingType();
export class Address
id: number = 0;
description: string = '';
export class BuildingType
id: number = 0;
description: string = '';
如您所见,Building 类包含其他类,例如 Address 和 BuildingType,它们还具有其他属性,例如 id 和 description。
在创建表单时,我在组件 ts 文件中使用了以下代码:
buildingForm: FormGroup;
construct(private fb: FormBuilder)
this.buildingForm = this.createBuildingFG(new Building);
createBuildingFG(building: Building)
let formGroup : FormGroup;
formGroup = this.fb.group(building);
// Because object of type "building" contain properties of non-primitive
// types such as object Address and BuildingType I think the following
// additional lines are required.
formGroup.controls.address = this.fb.group(building.address);
formGroup.controls.buildingType = this.fb.group(building.buildingType);
return formGroup;
这就是表单绑定到 html 模板的方式:
<form [formGroup]="buildingForm">
<label>
Door count:
<input formControlName="doorsCount" >
</label>
<label>
Building description:
<input formControlName="description" >
</label>
<label formGroupName="address">
Address:
<input formControlName="description" >
</label>
<label formGroupName="buildingType">
Building type:
<input formControlName="description" >
</label>
</form>
现在问题出现了,当我输出整个表单的值时,该值并没有真正根据在 formGroup 内的嵌套字段控件中键入的内容进行更新,例如地址或 buildingType。否则正常更新。
这是输出值的方式
<div>
buildingForm.value | json
</div>
但是,如果 createBuildingFG 函数的执行方式不同,并且每个 formControl 都是显式创建的,而不只是传递整个对象,则表单会正常运行。示例:
createBuildingFG(building: Building)
let formGroup : FormGroup;
formGroup = this.fb.group(
doorsCount: '',
description: '',
address: this.fb.group( description: ''),
buildingType: this.fb.group( description: '')
);
return formGroup;
任何人都可以解释发生了什么?显然,为了避免执行显式定义 fromGroup 的每个元素的繁琐任务,我们希望只传递整个对象。
【问题讨论】:
猜测一下,因为初始构造会执行您随后不会覆盖的事情。为什么不构建对象的副本然后将整个东西传递给表单构建器?通过解构,它应该相当整洁。 感谢@jonrsharpe,这是一个有趣的方法。你能告诉我在这种情况下如何进行解构吗?这对我来说相当混乱。 我个人会避免将数据对象作为配置对象传递给FormBuilder.group
。它可能适用于最简单的示例(例如具有所有原始字段且不需要验证的普通对象),但大多数时候您需要的不仅仅是这些。
【参考方案1】:
正如@jonrsharpe 在 cmets 中提到的那样
因为最初的构造会做一些你后来不会做的事情 覆盖。
那是什么?
当 Angular 创建 FormGroup 的新实例时,它会调用 _setUpControls
方法
export class FormGroup extends AbstractControl
constructor(
public controls: [key: string]: AbstractControl,
validatorOrOpts?: ValidatorFn|ValidatorFn[]|AbstractControlOptions|null,
asyncValidator?: AsyncValidatorFn|AsyncValidatorFn[]|null)
super(
coerceToValidator(validatorOrOpts),
coerceToAsyncValidator(asyncValidator, validatorOrOpts));
this._initObservables();
this._setUpdateStrategy(validatorOrOpts);
this._setUpControls(); <--------------
现在让我们看看方法:
/** @internal */
_setUpControls(): void
this._forEachChild((control: AbstractControl) =>
control.setParent(this);
control._registerOnCollectionChange(this._onCollectionChange);
);
我们可以看到每个控件项都设置了父项并注册了一些事件,但您不这样做。
以下代码应该可以工作:
formGroup = this.fb.group(building);
formGroup.controls.address = formGroup.controls.buildingType = null;
formGroup.registerControl('address', this.fb.group(building.address));
formGroup.registerControl('buildingType', this.fb.group(building.buildingType));
或者你可以使用递归来完成它:
constructor(private fb: FormBuilder)
this.buildingForm = this.createFormGroup(new Building);
createFormGroup(obj: any)
let formGroup: [id: string]: AbstractControl; = ;
Object.keys(obj).forEach(key =>
formGroup[key] = obj[key] instanceof Object ? this.createFormGroup(obj[key]) : new FormControl(obj[key]);
);
return this.fb.group(formGroup);
【讨论】:
谢谢它的工作!我使用了非递归方法。以上是关于角度 4 将包含其他对象的对象传递给 FormBuilder.group 函数会导致奇怪的表单行为的主要内容,如果未能解决你的问题,请参考以下文章