angular 4 将包含其他对象的对象传递给 FormBuilder.group 函数会导致奇怪的表单行为

标签 angular angular2-forms angular-forms

创建由以下“嵌套对象”(建筑物)组成的嵌套表单:

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 类包含其他类,例如 AddressBuildingType,它们还具有其他属性,例如 id说明

在创建表单时,我在组件 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;
}

这就是表单绑定(bind)到 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 内的嵌套字段控件中键入的内容进行更新,例如 address 或 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 在评论中提到的

because the initial construction does things you're not subsequently overriding.

那么这些东西是什么?

当 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);
}

关于angular 4 将包含其他对象的对象传递给 FormBuilder.group 函数会导致奇怪的表单行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45665480/

相关文章:

Angular 2+ Material mat-chip-list formArray验证

Angular 7 Forms - 有条件地需要 FormGroup

Angular2 根据 css 属性/屏幕大小更改操作

angular - 如何在 gRPC Angular 应用程序中使用 typescript protobuf 生成的文件

javascript - Angular2 响应式(Reactive)默认输入值

Angular 2 - 输入掩码 : Input box display formatted value, 而模型保留未格式化的值

angular - 如何使用 Angular 表单创建可编辑的 primeNG 表?

Angular:从 FormControl 获取所有验证器的列表

angularjs - 共享服务,组件通信Angular 2

Angular2 动画 - 动画不透明度,但不是显示属性