"Expression changed after validation" when a child component comes from ngOnInit

I have a parent component that displays a list of validation errors and displays a list of child components with ngFor . Each child component performs validation during ngOnInit and outputs the result to the parent component. The parent component listens for this output and updates the list of validation errors, the result of which causes an error:

Expression has changed after it was checked

Now I understand why this error occurs - at the beginning of the change detection cycle, the verification errors were in one state, and at the end they were in a different state, and this is not allowed.

I do not understand how to get around this problem. The parent component should display a list of errors at the top of the page, and each child component will add validation results to this list. If this is a violation of the unidirectional data stream, please tell me how to get around this in a clean way (i.e. do not wrap the check in setTimeout without changing from an immutable list to a mutable one, rather than explicitly invoking the change detector again after checking).

Plunker reproduces the problem: https://plnkr.co/edit/q52A1DraNOnxZa0qGFDo?p=preview


EDIT

I "solved" the problem by building an EventEmitter with the isAsync flag:

new EventEmitter(true)

This means that the values ​​will be emitted asynchronously, so the outgoing values ​​will be selected in the next change detection cycle. I think the result is the same as porting the logic to setTimeout , but in this way, at least we don’t need to port our code to a timeout wherever we can emit a value.

+6
source share
2 answers

Angular doesn't like it when change detection itself causes change, and ngOnInit is called change detection.

In devMode change detection, an additional change detection run is run after each regular change detection run to check if the model is stable. If the model changes while detecting changes, it throws this error.

You can defer a change until change detection is established using

  ngOnInit() { setTimeout(() => { this.output.emit({value: true}); } } 

Plunger example

Update (see Ghetolay comment below)

ngOnInit not called by change detection, and you can make changes to it. What you cannot do is make the parent change the child of ngOnInit , which will break the unidirectional data stream.

See also https://github.com/angular/angular/issues/10131#issuecomment-233369491

+3
source

You are not allowed to change anything in ngOnInit . The Angular 2 team refused to treat this as an error ( # 10131 ), so yes, you have to do it in an unclean way: setTimeout(..., 0) or Promise.resolve().then(...) .

0
source

Source: https://habr.com/ru/post/1014921/


All Articles