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
Make data
an Observable array
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?
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); }); }
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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With