Issue
When using the AsyncPipe
inside of an *ngIf
, if the Observable
connected to the AsyncPipe
pushes its values before the *ngIf
becomes true, the value returned from the AsyncPipe
will be incorrect.
For example, let’s say I have:
<div *ngIf="showPipe">
<div *ngFor="let item of arrObs | async">{{item}}</div>
</div>
Then say events happen in this order:
showPipe
is falsearrObs
pushes [1,2,3]showPipe
is set to true
From what I’ve seen, the *ngFor
will act as if arrObs | async
returned null.
One solution to this problem is to use [hidden]
instead, but there are a lot of benefits to *ngIf
, like performance and making null handling easier.
What’s the proper way to do this? Should I just not use an observable at all for displaying content? I had assumed that using an observable was the most Angular-y way of doing things.
Edit:
My observable is actually just a new Subject()
which I call next()
on.
Solution
There are some ways you can solve this. I would suggest adding a shareReplay
operator on your Observable
:
readonly arrObs = this.someDataFromSomewhere().pipe(
shareReplay(1)
);
if your Observable
is actually a Subject
, you can also change it to a BehaviorSubject
or ReplaySubject
This way you will always receive the most up to date data on subscription.
There are also ways to handle this in the template and still maintain the *ngIf
benefits:
<ng-container *ngIf="arrObs | async as arr">
<div *ngIf="showPipe">
<div *ngFor="let item of arr">{{item}}</div>
</div>
</ng-container>
Or if you don’t want the *ngIf
to wait for the observable
<ng-container *ngIf="{ arr: arrObs | async } as data">
<div *ngIf="showPipe">
<div *ngFor="let item of data.arr">{{item}}</div>
</div>
</ng-container>