Reputation: 3509
I've faced with very strange behaviour of change detector (with OnPush). I am not even able to explain it to myself and don't know how to fix it. Nevertheless I've reproduced this behaviour in very simple example on stackblitz
https://stackblitz.com/edit/angular-h28cw8
There are three components: main app
component, data
component and loading indicator
component. Main component can display the data
component through the <router-outlet>
when user click the Go to data
link. There is also service (aka state of the application). When user click Go to data
, the data
component requests this service for data, which is loaded with some delay. To emulate this delay I use rxjs timer, but with HttpClient
the behaviour is absolutely the same. Data & loading values are binded by the use of async
pipe. But for some reason data is displayed as expected, but loading
isn't (it's better to say that it works from time to time, but not always). That causes the loading indicatior doesn't appear on the screen. I also log values to the console where it's easy to see that the loading$
observable emits value, but the @Input
binding doesn't work for some reason. Why it works so, and how to fix that?
Upvotes: 1
Views: 879
Reputation: 214007
The reason why it is not working is because you're emitting this._loading.next(true)
value from child component after parent component has been checked.
Async pipe does triggers subscription and works as intended, that is runs cdRef.markForCheck();
. But it doesn't run change detection but rather only marks component, where AsyncPipe is used, to be checked. Once a new change detection cycle starts your component will recognize input changes.
To fix it you can wrap this._common.getData()
in microtask in your child component
Promise.resolve().then(() => {
this._common.getData();
});
Upvotes: 1