web-dev-qa-db-ja.com

親からFormGroupを再初期化するとカスタムコンポーネントFormControlが破損する

カスタムコンポーネントで使用されている親コンポーネントからformGroupを再初期化するときに問題が発生しました。私が得るエラーは:

名前が「selectedCompany」のフォームコントロール要素にアタッチされたFormControlインスタンスはありません

[〜#〜] 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# implement-controlvalueaccessor

コンポーネント

これはformGroup変数addFormを初期化するコードです:

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

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

addFormが初めて初期化されたときはすべて問題ありません。しかし、フォームが配置されている場所でモーダルを再度開き、同じコンポーネントコードが実行されると、上記のエラーが発生します。

16
Mario Petrovic

コンポーネントが古い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への参照が失われないようにしたので、エラーは発生しません。

18
Mario Petrovic

そのための私の解決策は、formControlNameformControlで置き換えることです。

の代わりに

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

使用する

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

または、formControlを取得するためのいくつかのgetMethod

エラーでも機能します:

パスを持つフォームコントロール要素に接続されたFormControlインスタンスがありません

いくつかのFormArrayを使用しました。

9
zucker

これに対する奇妙な「解決策」を見つけました。そのため、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();

変更を検出すると、同期的に変更検出が実行され、ビューが更新されるため、古いフォームグループが削除されます。

2