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

Custom component FormControl breaking if reinitializing FormGroup from parent

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

There is no FormControl instance attached to form control element with name: '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 初始化一切正常。但是当我重新打开窗体所在的模态,并执行相同的组件代码时,出现上述错误。

我发现一遍又一遍地重新初始化 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,所以不会发生错误。

我找到了一个奇怪的“解决方案”。因此,要重置使用 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 组件自行销毁并重新初始化,但危急时刻需要采取危急措施...

我需要这个 hack,因为我使用 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();

检测更改将同步 运行 更改检测和更新视图,从而删除旧的表单组。

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

而不是

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

使用

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

或使用一些 getMethod 获取 formControl

也适用,但有错误:

There is no FormControl instance attached to form control element with path

我用了一些 FormArray