'Why does Angular trigger ChangeDetection on parent components on DOM events despite OnPush strategy?
trick question I haven't found any answer in the documentation yet.
OnPush
strategy is known to trigger ChangeDetection in the following cases :
- when a DOM event the component listens to was received
- when the
|async
pipe receives a new event - when an
@Input()
- when
ChangeDetectorRef::markForCheck
is explicitly called (or any other similar methods like,ApplicationRef::tick
,ChangeDetectorRef::detectChanges
So when a DOM event is triggered on a component, it won't affect CD on a sibling component.
BUT it will be triggered on every parent component in his hierarchy wether Default
or OnPush
. This does not happend when calling detectChanges
for example where only the component gets CD.
I also noted, ApplicationRef.tick()
will only trigger CD on non-OnPush components.
Why doesn't OnPush
provide total isolation and still trigger CD on parents ?
Please see a working illustration on stackblitz
Solution 1:[1]
Maybe you have the same misunderstanding about OnPush that I had when I started learning about change detection :). The point is: the OnPush strategy does not change anything about which events trigger a CD cycle. This is solely taken care of by zone.js by patching browser APIs. (Unless CD is triggered manually.) zone.js does not care about components and ChangeDetectionStrategies. And CD always starts at the root as @Chris Hamilton explained.
The difference in ChangeDetectionStrategy.Default and OnPush is only if the component will actually be CHECKED during a CD cycle.
So the sentence in your original post should rather be: "OnPush strategy is known to only mark a component to be checked in the following cases".
See below an example that I observed with the profiler of the Angular DevTools. I put a setTimeout(() => {}, 6000)
in the ngOnInit of the OnPush component, it triggered a CD cycle (the source is "setTimeout"), but it did not cause the component itself to be checked.
About the differences between manually triggered detectChanges(), tick() and markForCheck():
ChangeDetectorReference.detectChanges()
triggers CD on this component and its children by respecting the CD strategy of the childrenApplicationRef.tick()
triggers CD for the whole application by respecting CD strategiesChangeDetectorReference.markForCheck()
does NOT trigger CD, but marks all OnPush parents to be checked once in the current or next CD cycle
(well explained here)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |