While using ChangeDetectionStrategy.OnPush
observables$
that are updated within ngAfterViewInit
on children components do not have their values reflected correctly within their respective html
templates.
@Component({
selector: 'app-example',
template: `exampleOne$ that does update - {{exampleOne$ | async}}
exampleTwo$ that doesn't update - {{exampleTwo$ | async}}
<button (click)="update()">Update</button>`,
styleUrls: ['./example.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ExampleComponent implements OnChanges, AfterViewInit {
readonly exampleOne$ = new BehaviorSubject(false);
readonly exampleTwo$ = new BehaviorSubject(false);
@Input() someValue = '';
ngOnChanges(): void {
// Reflected correctly within the template
this.exampleOne$.next(true);
}
ngAfterViewInit(): void {
// Reflected incorrectly within the template
this.exampleTwo$.next(true);
}
update(): void {
// Reflected correctly within the template
this.exampleTwo$.next(true);
}
}
Exception - If the component is included at the root of the application within app.component.html
the values are reflected correctly.
If used in any other context such a child component within a parent component then the exampleTwo$
observable will remain as false
until some other event triggers a change detection cycle.
Why does updating an observable$
inside ngAfterViewInit
not stay within Angular's zone, I'm aware of most of the limiting factors when using OnPush
regarding when and when it doesn't trigger a change detection cycle, but I can't find any decent information regarding it's lack of compatibility with ngAfterViewInit
Excerpt from - https://blog.angular-university.io/onpush-change-detection-how-it-works/
An OnPush change detector gets triggered in a couple of other situations other than changes in component Input() references, it also gets triggered for example:
if an observable linked to the template via the async pipe emits a new value