I am using an observable to return a list from service to my component and in my component I am using ChangeDetectionStrategy.OnPush and in template I am using async pipe, hoping this would give some performance benefit since Change Detection isn't performed all the time but only when new contents are available.
Below is my service:
import { Injectable, Inject, EventEmitter } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Subject } from 'rxjs/Subject';
@Injectable()
export class ListService {
public _list$: Subject<any[]>;
private list: any[] = [];
constructor() {
this._list$ = <Subject<any>>new Subject();
}
get list$() {
return this._list$.asObservable();
}
loadList() {
//if this.list is populated through an http call the view is updated,
//if its a static list like below, it doesn't trigger view update.
//this.list = ['Red', 'Green', 'Yellow', 'Blue'];
this._list$.next(this.list);
}
}
In my component I have:
import { Component, ChangeDetectionStrategy } from '@angular/core';
import { Observable } from 'rxjs/Observable';
@Component({
templateUrl: `
<ul>
<li *ngFor="let item of (list$ | async);">
{{item}}
</li>
</ul>
`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ListComponent {
public list$: Observable<any[]>;
constructor(
private _ls: ListService
) {}
ngOnInit() {
this.list$ = this._ls.list$;
this._ls.loadList();
}
}
The issue if the loadList contents fetch list contents through an http call, the view is updated, if the list content are static, the view isn't updated.
If I wrap list update inside setTimeout, it does trigger view update
setTimeout(() => {
this._list$.next(this.list);
}, 1);
I just started exploring Observables, can anyone please guide whats wrong with above code?
Async pipe does't trigger changeDetection and do not redraw value in UI.
OnPush means that the change detector's mode will be set to CheckOnce during hydration. Default means that the change detector's mode will be set to CheckAlways during hydration.
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 a component event handler gets triggered. if an observable linked to the template via the async pipe emits a new value.
By default, pipes are defined as pure so that Angular executes the pipe only when it detects a pure change to the input value. A pure change is either a change to a primitive input value (such as String , Number , Boolean , or Symbol ), or a changed object reference (such as Date , Array , Function , or Object ).
Just move the code fron ngOnInit()
to the constructor. Angular tries to resolve the binding (subscribe to the observable) before ngOnInit()
is called and fails because thod._list$
is null
and doesn't try later because it doesn't recognise the change.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With