2017-08-13 6 views
4

私の反応性フォームは、3つのコンポーネントレベルの深いです。親コンポーネントはフィールドを持たない新しいフォームを作成し、子コンポーネントに渡します。動的ネストされた反応形式:ExpressionChangedAfterItHasBeenCheckedError

最初は外側の形式が有効です。後で子コンポーネントは、外部フォームを無効にするバリデーター(失敗した)を含む新しいフォーム要素を追加します。

私はコンソールにExpressionChangedAfterItHasBeenCheckedErrorエラーを取得しています。私はそのエラーを修正したい。

これはどういうわけか、これはネストの3番目のレベルを追加したときにのみ発生します。同じアプローチが、2つのレベルの入れ子で機能するように見えました。

Plunker:https://plnkr.co/edit/GymI5CqSACFEvhhz55l1?p=preview

親コンポーネント

@Component({ 
    selector: 'app-root', 
    template: ` 
    myForm.valid: <b>{{myForm.valid}}</b> 
    <form> 
     <app-subform [myForm]="myForm"></app-subform> 
    </form> 
    ` 
}) 
export class AppComponent implements OnInit { 
    ... 

    ngOnInit() { 
    this.myForm = this.formBuilder.group({}); 
    } 
} 

サブコンポーネント

@Component({ 
    selector: 'app-subform', 
    template: ` 
    <app-address-form *ngFor="let addressData of addressesData;" 
     [addressesForm]="addressesForm"> 
    </app-address-form> 
    ` 
}) 
export class SubformComponent implements OnInit { 
    ... 

    addressesData = [...]; 

    constructor() { } 

    ngOnInit() { 
    this.addressesForm = new FormArray([]); 
    this.myForm.addControl('addresses', this.addressesForm); 
    } 

子コンポーネント

@Component({ 
    selector: 'app-address-form', 
    template: ` 
    <input [formControl]="addressForm.controls.addressLine1"> 
    <input [formControl]="addressForm.controls.city"> 
    ` 
}) 
export class AddressFormComponent implements OnInit { 
    ... 

    ngOnInit() { 
    this.addressForm = this.formBuilder.group({ 
     addressLine1: [ 
     this.addressData.addressLine1, 
     [ Validators.required ] 
     ], 
     city: [ 
     this.addressData.city 
     ] 
    }); 

    this.addressesForm.push(this.addressForm); 
    } 
} 

enter image description here

+0

チェック[あなたは 'ExpressionChangedAfterItHasBeenCheckedError'エラーについて知る必要があるすべてのもの](https://blog.angularindepth.com/everything-you-need-to-know-about-the-expressionchangedafterithasb eencheckederror-error-e3fd9ce7dbb4)記事 –

+0

私はそのページを過去24時間で5回訪問しました;)まだそれを修正する方法はまだ分かりません。 –

+0

あなたが参照したプランナーにエラーはありません –

答えて

5

Everything you need to know about the ExpressionChangedAfterItHasBeenCheckedError error記事を読むために必要な問題を理解するために。

具体的には、AppComponentにフォームを作成し、DOM内で{{myForm.valid}}補間を使用しているという問題があります。これは、DOMを更新するAppComponentのAngular will run create and run updateRenderer functionを意味します。そして、あなたは、このフォームにコントロールしてサブグループを追加するには、サブコンポーネントのngOnInitライフサイクルフックを使用する:あなたは初期値を指定しないと、あなたが必要なバリデータを指定するため

export class AddressFormComponent implements OnInit { 
    @Input() addressesForm; 
    @Input() addressData; 

    ngOnInit() { 
    this.addressForm = this.formBuilder.group({ 
     addressLine1: [ 
     this.addressData.addressLine1, 
     [ Validators.required ] <----------- 
     ] 

    this.addressesForm.push(this.addressForm); <-------- 

コントロールが無効になります。したがって、フォーム全体が無効になり、式{{myForm.valid}}falseと評価されます。しかし、AngularがAppComponentの変化検出を実行したとき、それはtrueと評価されました。そしてそれがエラーの内容です。

必要なバリデーターを追加する予定であるため、最初にフォームを無効としてマークすることができますが、Angularはそのような方法を提供していないようです。おそらく、非同期にコントロールを追加することをお勧めします。

const resolvedPromise = Promise.resolve(null); 

@Component({ 
    ... 
export class AddressFormComponent implements OnInit { 
    @Input() addressesForm; 
    @Input() addressData; 

    addressForm; 

    ngOnInit() { 
    this.addressForm = this.formBuilder.group({ 
     addressLine1: [ 
     this.addressData.addressLine1, 
     [ Validators.required ] 
     ], 
     city: [ 
     this.addressData.city 
     ] 
    }); 

    resolvedPromise.then(() => { 
     this.addressesForm.push(this.addressForm); <------- 
    }) 
    } 
} 

またはフォーム状態を保持するためにAppComponentにいくつかの変数を使用し、それを使用する:あなたはそれがされる場合のだから、

const resolvedPromise = Promise.resolve(null); 

export class NgForm extends ControlContainer implements Form { 
    ... 

    addControl(dir: NgModel): void { 
    // adds controls asynchronously using Promise 
    resolvedPromise.then(() => { 
     const container = this._findContainer(dir.path); 
     dir._control = <FormControl>container.registerControl(dir.name, dir.control); 
     setUpControl(dir.control, dir); 
     dir.control.updateValueAndValidity({emitEvent: false}); 
    }); 
    } 

:実際には、これは角度がソース自体に何をするかでありますテンプレート:

{{formIsValid}} 

export class AppComponent implements OnInit { 
    myForm: FormGroup; 
    formIsValid = false; 

    constructor(private formBuilder: FormBuilder) {} 

    ngOnInit() { 
    this.myForm = this.formBuilder.group({}); 
    this.myForm.statusChanges((status)=>{ 
     formIsValid = status; 
    }) 
    } 
} 
+0

非常に詳細な回答ありがとう!感謝します。 –

+0

@ErikNijland、歓迎です)幸運 –

+0

アーカイブについて:最初のアプローチは完璧に機能しました。 2番目は動作しませんでした。同じエラーを別の変数に移動しました。また、statusChangesを確認するには購読が必要です。 –

関連する問題