Reputation: 25397
I'm haunted by this exception and I just don't get what the problem here is. I have a FormArray
which pushes new items to its controls. These controls are passed down to other child components:
<mat-card *ngFor="let itemFormGroup of formArray.controls">
<app-item [formGroup]="itemFormGroup">
</app-item>
</mat-card>
However, I've tried several things but it's just not working. I've now tried to use EventEmitter<any>(true)
as well as setTimeout()
etc but I'm am not getting rid of this exception
@Output()
addItem = new EventEmitter<any>(true);
onMenuSelected(item) {
this.addItem.emit({date: this.date, item: item});
}
The parent:
onAddItem(event) {
const formArray = <FormArray> this.form.get(event.date);
formArray.push(this._formBuilder.group(event.item));
}
The error:
ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'ng-valid: true'. Current value: 'ng-valid: false'.
Since I am not setting any property named valid
, I assume it's the form itself which changes that property during the cycle and breaks things.
How can I avoid this?
This is how the FormArray
gets constructed by the parent. The whole thing is a calendar which is basically a huge FormGroup
taking the form
// pseudo code
form: FormGroup { // Form of the entire calendar
date1: FormArray [ // First day in the calendar with a list of items
item1: FormGroup, // An item in the calendar
item2: FormGroup
],
date2: FormArray [
]
}
Here's the logic that builds it:
refreshCalendar() {
const groups = {};
this.dates.forEach(d => {
groups[d] = this._formBuilder.array([]);
});
if (Object.keys(groups).length > 0) {
this.form = this._formBuilder.group(groups);
}
this.formValueChange$ = this.form.valueChanges.subscribe(() => {
setTimeout(() => {this._calendarComponentService.setDirty(this.form.dirty);}, 0);
});
// This call is important after resetting in order to propagate the 'dirty' state
this.form.updateValueAndValidity();
this.updateItems();
}
updateItems() {
if (Object.keys(this.items).length > 0) {
for (const k of Object.keys(this.items)) {
const formArray = <FormArray> this.form.get(k);
if (formArray == null) {
continue;
}
for (const item of this.items[k]) {
formArray.push(this._formBuilder.group(item));
}
}
}
}
Upvotes: 1
Views: 569
Reputation: 522
Try injecting ChangeDetectionRef and call detectChanges() after you insert the new item.
Upvotes: 1