如果从父级重新初始化FormGroup,则自定义组件FormControl会中断

时间:2017-06-01 08:24:55

标签: angular angular-components

从我的自定义组件中使用的父组件重新初始化formGroup时出现问题。我得到的错误是:

  

表单控件元素没有附加FormControl实例   名称:'selectedCompany'

HTML

<form [formGroup]="addForm">
     ...
     <my-custom-component formControlName="selectedCompany"></my-custom-component>
     ...
</form

<my-custom-component>是根据创建自定义formControl组件的有效方式创建的:https://blog.thoughtram.io/angular/2016/07/27/custom-form-controls-in-angular-2.html#implementing-controlvalueaccessor

组件

这是初始化formGroup变量addForm

的代码
let formTemp: any = {
    selectedCompany: new FormControl(null, [Validators.required]),
}

this.addForm = this._formBuilder.group(formTemp);

第一次初始化addForm一切都很好。但是当我重新打开表单所在的模态,并执行相同的组件代码时,会出现上述错误。

3 个答案:

答案 0 :(得分:15)

我发现反复重新初始化formGroup并不好,因为组件会丢失对旧formGroup的引用。

如果设置值是显示新表单所需的值,.setValue就是这里的解决方案:

<强>组件

不是重新初始化addForm,而是检查先前是否已初始化addForm,如果是,则仅为现有FormControls设置值:

if (this.addForm) {
    this.addForm.setValue({
        selectedCountry: null
    })
} else {

    let formTemp: any = {
        selectedCompany: new FormControl(null, [Validators.required]),
    }

    this.addForm = this._formBuilder.group(formTemp);
}

通过这种方式,我想,旧addForm的引用不会丢失,因此不会发生错误。

答案 1 :(得分:1)

我找到了一个奇怪的“解决方案”。因此,要重置子组件,这些子组件将使用formGroup并在换出时感到困惑。我使用这个技巧。

comp.ts

public flicker: boolean = false;

reInit() {
    this.flicker = true;

    this.addForm = this._formBuilder.group({
         selectedCompany: new FormControl(null, [Validators.required]),
    });

    setTimeout( () => this.flicker = false, 200); //On very heavy pages, timeout ensures that the flicker hack works as expected.
}

comp.html

<form [formGroup]="addForm" *ngIf="!flicker">
     ...
     <my-custom-component formControlName="selectedCompany"></my-custom-component>
     ...
</form>

可怕的黑客,它基本上强制formGroup组件销毁并重新初始化自身,但绝望的时代要求采取绝望的措施...

我需要这个技巧,因为我使用FormGroup对象将表单的结果保存到临时结果数组中,每个结果都可以随意重新打开和编辑。将来,为了避免这个问题,我将基于ngModel的表单状态进行保存,但是这里有一个临时解决方案。

编辑1

setTimeout( () => this.flicker = false, 200); //On very heavy pages, timeout ensures that the flicker hack works as expected.

有一种更好的同步闪烁方式

this.flicker = true;
this._changeDetectorRef.detectChanges();
this.flicker = false;
this._changeDetectorRef.detectChanges();

detect changes将同步运行变更检测并更新视图,从而删除旧的表单组。

答案 2 :(得分:1)

为此,我的解决方案是将formControlName替换为formControl

代替

<my-custom-component formControlName="selectedCompany"></my-custom-component>

使用

<my-custom-component [formControl]="addForm.controls['selectedCompany']"></my-custom-component>

或使用一些getMethod来获取formControl

也会出现错误:

  

没有任何FormControl实例附加到带有   路径

我使用过一些FormArray