in ParentComponent =>
ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: ''. Current value: '[object Object]'.
at viewDebugError (vendor.bundle.js:8962)
at expressionChangedAfterItHasBeenCheckedError (vendor.bundle.js:8940)
Parent component Html
<div>
<app-child-widget [allItems]="allItems" (notify)="eventCalled($event)"></app-child-widget>
<div>
Parent component
export class ParentComponent implements OnInit {
returnedItems: Array<any> = [];
allItems: Array<any> = [];
constructor(
) { }
ngOnInit() {
this.allItems = // load from server...
}
eventCalled(items: Array<any>): void {
this.returnedItems = items;
}
}
Child component
@Component({
selector: 'app-child-widget',
templateUrl: 'child.component.html',
styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit {
@Output() notify: EventEmitter<any> = new EventEmitter();
@Input() private allItems: Array<any>;
constructor() { }
ngOnInit() {
doSomething();
}
doSomething() {
this.notify.emit(allItems);
}
}
Debugging the errorlink The source maps generated by the CLI are very useful when debugging. Navigate up the call stack until you find a template expression where the value displayed in the error has changed. Ensure that there are no changes to the bindings in the template after change detection is run.
The article Everything you need to know about the ExpressionChangedAfterItHasBeenCheckedError
error explains this behavior in great details
Your problem is very similar to this one but instead of updating parent property through a service you're updating it through synchronous event broadcasting. Here is the quote from the linked answer:
During digest cycle Angular performs certain operations on child directives. One of such operations is updating inputs and calling ngOnInit lifecycle hook on child directives/components. What's important is that these operations are performed in strict order:
- Update inputs
- Call ngOnInit
So in your case Angular updated input binding allItems
on child component, then called onInit
on child component which caused an update to allItems
of parent component. Now you have data inconsistency. Parent component has one value while the child another. If Angular continues synchronizing changes you'll get an infinite loop. That's why during next change detection cycle Angular detected that allItems
was changed and thrown an error.
It seems that this is an application design flaw as you're updating details
from both parent and child component. If it's not, then you can solve the problem by emitting the event asynchronously like this:
export class ChildComponent implements OnInit {
@Output() notify: EventEmitter<any> = new EventEmitter(true);
^^^^^^-------------
But you have to be very careful. If you use any other hook like ngAfterViewChecked
that is being called on every digest cycle, you'll end up in cyclic dependency!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With