Recently I've been learning and experimenting with angular change detection. What I found out is that it's much different than it's described in most articles and documentation, especially regarding onPush components.
Example of behaviour that I didn't find described anywhere: Let's say we have component detached from change detection, and it has onPush child.
- When we manually trigger change detection in parent, child will remain unchanged.
- When we fire some event in child, change detection will not be triggered there either, because change detection propagation goes from top to bottom, and is stopped on detached parent.
- However, when we first fire some event in child, and then run detectChanges() in parent, child will run change detection.
Here's example: https://stackblitz.com/edit/angular-pj9bun?file=src%2Fapp%2Fparent%2Fparent.component.ts
For me it looks like there are 2 phases. First, components are marked for change. Starting from component that fired event, going to root, and propagating to all non onPush components. Then, real change detection occurs, starting from root, propagating through all components that are marked for change. This would explain why OnPush component form my example only had change detection run when I clicked its button before-hands. It also seems plausible because even changeDetectorRef has method markForCheck() that does something similar.
But this is just my theory, I didn't find it spcecified in any documentation, or even article. Is there something like that? This would help me better understand how change detection works overall
The calls to detach() and detectChanges() in the parent will not work in the child unless the child uses one of the methods below:
<app-child value={{sharedService.value}}>
then you don't need the ChangeDetectorRef.
<label *ngIf=value$ | async as value>child shared service value: {{value}}</label>
<label>child shared service value: {{sharedService.value}}</label>
is not a direct descendent of the parent component and doesn't implement any of the above steps so its not marked.In the example provided, you would need to monitor the sharedService and call ChangeDetectorRef from the child itself to force a detach/update, so you might as well make value an observable and bind to the observable via async pipe (#2 above).