Search code examples
rxjsangular2-httpangular2-observables

Rxjs how to invoke cold Observables


The blow code is from the bookexist route guard in ngrx/example I understand that it is calling the googleBooks service to make a http request and check if the book is already in the store. The part that I can't understand is that it is not calling subscribe anywhere in the guard service. My understanding is that http Observables in Anuglar2 are considered as cold Observables which means they won't get invoked until someone subscribe to it.

My question is: how is the below googleBooks service getting invoked?

hasBookInApi(id: string): Observable<boolean> {
  return this.googleBooks.retrieveBook(id)
    .map(bookEntity => new book.LoadAction(bookEntity))
    .do((action: book.LoadAction) => this.store.dispatch(action))
    .map(book => !!book)
    .catch(() => {
      this.router.navigate(['/404']);
      return of(false);
    });
}

Solution

  • It's called via the observable that's composed in the CanActivate implementation:

    /**
     * This is the actual method the router will call when our guard is run.
     *
     * Our guard waits for the collection to load, then it checks if we need
     * to request a book from the API or if we already have it in our cache.
     * If it finds it in the cache or in the API, it returns an Observable
     * of `true` and the route is rendered successfully.
     *
     * If it was unable to find it in our cache or in the API, this guard
     * will return an Observable of `false`, causing the router to move
     * on to the next candidate route. In this case, it will move on
     * to the 404 page.
     */
    canActivate(route: ActivatedRouteSnapshot): Observable<boolean> {
      return this.waitForCollectionToLoad()
        .switchMap(() => this.hasBook(route.params['id']));
    }
    

    CanActivate is an Angular interface and it's invoked by the router. The implementation of CanActivate can return an observable, a promise or a boolean. When it returns an observable, the router subscribes to it - which sees a subscription made to the observable that's composed within it and - eventually - to the observable returned by hasBookInApi that you have included in your question.