Solvedangular AsyncPipe breaks change detection when emitting from ngOnInit of child component

I'm submitting a ... (check one with "x")

[x] bug report => search github for a similar issue or PR before submitting
[ ] feature request
[ ] support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question

Current behavior

I have the following structure of components in my simple application:

  • App
    • Container
      • Emitter

The App component shows an observable value using the async pipe: {{ value | async }}.
The Emitter component emits a message on said observable: value.next('hello');
The Container component simply shows the Emitter component.

value is an RxJs ReplaySubject. The message is emitted from the Emitter's ngOnInit() method. This causes an ExpressionChangedAfterItHasBeenCheckedError when the change detection cycle runs.

Expected behavior

The async pipe should be able to handle messages emitted at any time without causing the ExpressionChangedAfterItHasBeenCheckedError.

Minimal reproduction of the problem with instructions

See http://plnkr.co/edit/zcWwamXvuwUPubFHaxSX

Open the dev console to see the error.

What is the motivation / use case for changing the behavior?

If the observable was hooked up to directly modify a property in the parent component, then the error would be understandable. However, I think it should be the job of the async pipe to handle incoming messages in such a way as to update the view at the right time. Otherwise, this responsibility is shifted to the code that emits the message, and this code might not even know it is used together with Angular.

Some comments on StackOverflow suggest using setTimeout() as a workaround. I managed to solve it by wrapping the emission in Zone.current.scheduleMicroTask(), which is just a little bit nicer.

We encountered this problem when upgrading to Angular 4.1.3 from Angular 2.4.4, where it worked without any problems.

The problem also doesn't occur if the Emitter component is a child right under the App component (removing the Container component).

Please tell us about your environment:

  • Angular version: 4.1.3
  • Browser: Tested on Chrome 57.0.2987.133
  • Language: TypeScript
12 Answers

✔️Accepted Answer

every time i encountered this error i solved it by piping a delay of 0 on the observable, i guess internally it uses settimeout

Other Answers:

@vicb I've reproduced it with Angular v6. Here's the link https://stackblitz.com/edit/angular-async-change-detection-error

I don't know a better way to avoid it as set setTimeout to leave current execution context. maybe some Zone magic could help

More Issues: