Solvedangular ngIf on Observable list length prevents ngFor to loop through Observable list with async pipe
✔️Accepted Answer
As for angular 4 try this
<ng-container *ngIf="heroes|async;let heroesItems">
<ul class="custom-dropdown" *ngIf="heroesItems.length > 0">
<li *ngFor="let hero of heroesItems">{{hero.name}}</li>
</ul>
</ng-container>
Other Answers:
Can confirm still an issue in release.
<div class="well" *ngIf="(users$ | async)?.length>0">
<div *ngFor="let user of users$ | async"
class="search-result" >
<a routerLink="/user/{{user.id}}" routerLinkActive="active">
{{user.given_name}} {{user.family_name}}</a>
</div>
</div>
The for routine is never triggered and the observed item never fires a network request.
@huiguang-liang Yes and by adding it, you changed the semantic of the search: The | async
pipe inside the *ngFor
will now subscribe to the hero
0bservable AFTER the search result has been received; there is no bug in angular here, but in your code!
Observables are by default cold and do NOT cache any value (unlike promises). That is, if you subscribe after an item is emitted you will not get that item. The solution is to turn the cold observable into a hot observable which cashes the last element using publishReplay(1).refCount()
. This is the only change I made (plus importing publishReplay) of your plunkr and now it works fine here: https://plnkr.co/edit/jjtJkTaEeFWZd8wKjP5O?p=preview
I agree that this issue is mostly about people not understanding RxJS/Observables; there is no real plunkr here that shows an issue in angular (except for relying on the hard to grasp RxJS which is another topic).
@huiguang-liang Look at my plunkr and try to understand the difference between hot and cold observables (and read about ReplaySubject vs. BehaviourSubject vs. Subject).
In case of an Observable array, in component template if we add *ngIf =" (list$ | async)?.length>0" it doesn't loops through the child *ngFor.
For example if I have below Observable list in the component:
list$: Observable<any[]>;
and below in template:
It seems that (list$ | async)?.length gives us the length of the list but the list isn't printed on the screen.
Whereas if I remove ngIf it start working: