[Fixed] Waiting for nested Observables from Store correctly in Angular 2

Issue

I’m trying to create a method with nested dependent observables, where the second one waits for the first one. And then returns a bool.

What the code is doing is:
gets list of assets from the store, gets the root asset, and then get the status from the database and then updates the UI.

But what happens is that the value of false is returned from the outer subscription first, and then the UI is updated correctly by the inner subscription like it’s supposed to. But it should return a value of true when it completes rather than returning a false before it completes.

I understand why this is, and I need to make the outer one wait. After looking at many other questions similar to this here, I have tried using switchMap and resultSelector. But I’m completely lost on how to use them correctly in this scenario, with tap.

Any advice would be appreciated.

getAndUpdateHexStatus (startTime, endTime): Observable<boolean> {
  this.store.pipe(
      select((assets) => assets.dashboard.assets), //get the assets
      tap((assets) => {
        var rootAsset = assets.filter((value) => this.isRootAsset(value)); //get the root asset
        if (rootAsset) {
          this.getDetailDataForAssetAndDates(rootAsset[0].assetId, new Date(startTime), new Date(endTime)) //get status data from the DB.
            .subscribe((data) => {
              this.updateAssetStatus(data); //Update the UI
              return of(true);
            });
        }

      }),
      takeUntil(this.componentDestroyed$)
    )
    .subscribe();
    return of(false);
}

Solution

You are close. You’re returning the of(false) immediately on the execution of the function, so it’s returned first.

Instead you need to use a higher order mapping operator like switchMap and within it’s body decide what to return. If the condition is true, then return the getDetailDataForAssetAndDates() with a map operator piped in to update the UI and return true. Or if the condition if false, use of() to return false because switchMap needs to return an observable.

getAndUpdateHexStatus(startTime, endTime): Observable<boolean> {
  return this.store.pipe(
    select((assets) => assets.dashboard.assets), //get the assets
    switchMap((assets: any) => {
      rootAsset = assets.filter((value) => this.isRootAsset(value));
      return (!!rootAsset)
        ? this.getDetailDataForAssetAndDates(rootAsset[0].assetId, new Date(startTime), new Date(endTime)).pipe(
            map(data => {
              this.updateAssetStatus(data);
              return true;
            })
          )
        : of(false)
    })
  );
}

Leave a Reply

(*) Required, Your email will not be published