Reputation: 63
I'm attempting to simulate latency with my observables.
I want to unwrap the observable using the async pipe, and add a bit of delay with the 'delay' operator.
app.component.html
<ul *ngIf="items$ | async as items">
<li *ngFor=let item of items">{{ item }}<li>
</ul>
app.component.ts
get items$(): Observable<string[]> {
return of(['alpha', 'bravo', 'charlie', 'delta']).pipe(delay(3000));
}
However, doing it in this fashion returns no HTML markup. Removing the pipe(delay(3000))
allows it to work.
If I implement 'OnInit' and just check on the observable:
ngOnInit(): void {
this.items$.subscribe(val => console.log(val));
}
In three seconds the console will output:
(4) ["alpha", "bravo", "charlie", "delta"]
So the observable is behaving like I want it to, but it seems I am not utilizing the async pipe correctly.
What am I missing about about how the async pipe works? How do I simulate this delay in a simple fashion?
Upvotes: 2
Views: 2813
Reputation: 62213
You need a single Observable instance. Your code currently will create and return a new Observable every time your property items$
is accessed. Create it one time instead. You could still use a getter if you wanted to as long as it is the same Observable instance being returned with each call.
items$: Observable<string[]>;
constructor() {
this.items$ = of(['alpha', 'bravo', 'charlie', 'delta']).pipe(delay(3000));
}
or
private _items$?: Observable<string[]>;
get items$(): Observable<string[]> {
if (!this._items$) {
this._items$ = of(['alpha', 'bravo', 'charlie', 'delta']).pipe(delay(3000));
}
return this._items$;
}
If you want to see how/why your original code is failing you could add a counter in the getter and then you can see the number of Observable being created and returned.
numberOfCalls = 0;
get items$(): Observable<string[]> {
this.numberOfCalls++;
return of(['alpha', 'bravo', 'charlie', 'delta']).pipe(delay(3000));
}
and then add this to your template
calls to items$ which create and return a new observable = {{numberOfCalls}}
Upvotes: 4