2017-08-13 219 views
4

我的反應形式是三個組件級別深。父組件創建一個沒有任何字段的新表單,並將其傳遞給子組件。動態嵌套反應形式:ExpressionChangedAfterItHasBeenCheckedError

首先,外形是有效的。稍後,子組件添加帶有驗證器的新表單元素(失敗),從而使外部表單無效。

我收到的控制檯ExpressionChangedAfterItHasBeenCheckedError錯誤。我想修復這個錯誤。

不知何故,這隻發生在我添加第三層嵌套。同樣的方法似乎適用於兩層嵌套。

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中使用插值。這意味着更新DOM的的角度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); 

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

所以你區分這將是:

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持有形式的國家,並用它在模板:

{{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

對於檔案:第一種方法完美無缺地工作。第二個沒有工作。它只是將相同的錯誤移動到另一個變量。還需要一個.subscribe來檢查statusChanges。 –