Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 4 async with loading and display when empty

I have an Angular component that gets a service CatalogServiceinjected:

export class CatalogListComponent implements OnInit {   catalog$: Observable<MovieResponseItem[]>;   constructor(private catalogService: CatalogService) {}   ngOnInit() {     this.catalog$ = this.catalogService.userCatalog;   } } 

This service returns an Observable<MovieResponseItem[]> on property userCatalog:

@Injectable() export class CatalogService {   get userCatalog(): Observable<MovieResponseItem[]> {     return this._userCatalogSubject.asObservable();   } } 

The MovieResponseItemis just a simple interface:

export interface MovieResponseItem {   title: string; } 

Now I want to iterate the items and display a loading animation while the catalog queries the underlying service for data (that takes some time) - this works. This is the template used:

<div *ngIf="(catalog$ | async)?.length > 0; else loading">    <ng-container *ngFor="let item of catalog$ | async">      <div>{{item.title}}</div>    <ng-container> </div> <ng-template #loading>loading animation...</ng-template> 

This obviously displays the #loading template while the async is awaiting data. If the observable returns data, it iterates over the catalog values.

But now I want to separate this into this behaviour:

  • while we await data, display the loading animation
  • if we have a response from the service and the returned list is empty, show an information text (like "your catalog is empty") and do not iterate (as there is no data)
  • if we have a response from the service and the returned list has values, iterate the items (as in current state)

How can I achive this? From what I read on similiar posts nobody tried to achieve that (or I did not find it).

Thanks a lot!

like image 459
dArignac Avatar asked Sep 26 '17 19:09

dArignac


2 Answers

 <div *ngIf="catalog$ | async as catalog; else loading">   <ng-container *ngIf="catalog.length; else noItems">     <div *ngFor="let item of catalog">{{item.title}}</div>   </ng-container>   <ng-template #noItems>No Items!</ng-template>  </div>  <ng-template #loading>loading animation...</ng-template> 

This should do the trick. Better to use as few async pipes as possible and just declare it "as" a template variable you can use where ever. Otherwise the stream will be executed once per async pipe which is a bad practice and could create unneeded http calls if this is http backed.

*edit for the syntax error

like image 134
bryan60 Avatar answered Sep 18 '22 15:09

bryan60


hmmm.. https://github.com/angular/angular/issues/14479

Just throw in another ngIf - else condition.

<div *ngIf="(catalog$ | async);  else loading;">    <div *ngIf="catalog$.length == 0; else empty;">       <ng-container *ngFor="let item of catalog$ | async">          <div>{{item.title}}</div>       <ng-container>    </div>    <ng-template #empty>empty animation...</ng-template> </div> <ng-template #loading>loading animation...</ng-template> 
like image 31
Pezetter Avatar answered Sep 21 '22 15:09

Pezetter