import { Injectable } from '@angular/core'; import { Observable } from 'rxjs/Observable'; import { Subject } from 'rxjs/Subject'; import 'rxjs/add/operator/combineLatest'; import 'rxjs/add/operator/mapTo'; import 'rxjs/add/operator/merge'; @Injectable() export class LoadingFailedService { private reloadSubject = new Subject(); public data$: Observable; public failed$: Observable; public loading$: Observable; constructor() {} public reload() { this.reloadSubject.next(true); } // setup the load-fail-service with a parameterstream and the function to be loaded/failed public setup(inputStream: Observable, promiseFunction: (any) => Promise) { const reload$ = this.reloadSubject.asObservable().startWith(true); const inputRequest$ = inputStream.combineLatest(reload$, (id, _) => id); const assignmentRequest$ = inputRequest$ // todo: find a better solution for this 'mapping to null on error' .switchMap(params => promiseFunction(params).catch(e => null)) .share(); const data$ = assignmentRequest$.filter(val => val !== null); const failedRequest$ = assignmentRequest$.filter(val => val === null); const loading$ = Observable.merge( inputRequest$.mapTo(true), assignmentRequest$.mapTo(false)); const failed$ = failedRequest$.mapTo(true) .merge(data$.mapTo(false)) .combineLatest(loading$, (failed, loading) => failed && !loading); this.loading$ = loading$; this.failed$ = failed$; this.data$ = data$; } }