Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 2 - Show loading-information when (observableData | async) is not yet resolved

Tags:

just as the title says, I want to embrace the power of rxjs Observables.

What I do now:

// dataview.html <div *ngIf="isLoading">Loading data...div> <ul *ngIf="!isLoading">     <li *ngFor="let d of data">{{ d.value }}</li> </ul>   // dataview.ts  data: any[] = []; isLoading: boolean = false;  getData() {  this.isLoading = true; this._api.getData().subscribe(         data => {             this.data = data;             this.isLoading = false;         },         error => {             this.error = error;             this.isLoading = false;         }); } 

What I want to do:

1. Use async pipe in my template

  1. Make data an Observable array

  2. Still display loading information for the user

I'm a big fan of clean code, so how can this be done nicely using rxjs and Angular 2?

like image 628
Alexander Ciesielski Avatar asked Jul 08 '16 08:07

Alexander Ciesielski


2 Answers

This is how I do it. Also i use $ at the and of the variable name to remind me that it is a stream.

// dataview.html <div *ngIf="isLoading$ | async">Loading data...</div> <ul *ngIf="!(isLoading$ | async)">     <li *ngFor="let d of data">{{ d.value }}</li> </ul>   // dataview.ts  data: any[] = []; isLoading$: BehaviorSubject<boolean> = new BehaviorSubject(false);  getData() {  this.isLoading$.next(true);  this._api.getData().subscribe(         data => {             this.data = data;         },         error => {             this.error = error;         },         complete => {             this.isLoading$.next(false);         }); } 
like image 52
Kliment Avatar answered Oct 19 '22 09:10

Kliment


I Came up with the following:

export enum ObsStatus {   SUCCESS = 'Success',   ERROR = 'Error',   LOADING = 'Loading', }  export interface WrapObsWithStatus<T> {   status: ObsStatus;   value: T;   error: Error; }  export function wrapObsWithStatus<T>(obs: Observable<T>): Observable<WrapObsWithStatus<T>> {   return obs.pipe(     map(x => ({ status: ObsStatus.SUCCESS, value: x, error: null })),     startWith({ status: ObsStatus.LOADING, value: null, error: null }),     catchError((err: Error) => {       return of({ status: ObsStatus.ERROR, value: null, error: err });     })   ); } 

And then in your component:

TS

public ObsStatus: typeof ObsStatus = ObsStatus;  public obs$: Observable<WrapObsWithStatus<YOUR_TYPE_HERE>> = wrapObsWithStatus(this.myService.getObs()); 

HTML

<div *ngIf="obs$ | async as obs" [ngSwitch]="obs.status">   <div *ngSwitchCase="ObsStatus.SUCCESS">     Success! {{ obs.value }}   </div>    <div *ngSwitchCase="ObsStatus.ERROR">     Error! {{ obs.error }}   </div>    <div *ngSwitchCase="ObsStatus.LOADING">     Loading!   </div> </div> 
like image 25
maxime1992 Avatar answered Oct 19 '22 10:10

maxime1992