Search code examples
angulartypescriptrxjsngrx

RXJS - Typescript - Await observable emit until another observable<boolean> is false


I currently have a solution that looks like this: When a user is navigating in a view an api call is executed to get the data for that specific view. That data is in turn later on used to determine whether a dialog should appear when a user is performing an action.

At the moment the solution is working but I can think of a potential problem when a user is having high latency and performs the above action before the api request finishes.
I do not want to display a loading indicator everytime the user navigates since it bothers the hell out of me when working with systems like that. I would rather have the user wait when she/he wants to perform the action.
Additionally I do have an observable which indicates whether the api request is loading or not which I am planning to use somehow.
The Code looks likes this with small alterations of the names for clarity.

actionPerformed$ = createEffect(() => 
      this.actions$.pipe(
        ofType(performAction),
        withLatestFrom(entities$),
        mergeMap(data => {
          let payload = data[0];
          let dataFromApi = data[1];
          ...
          ...
        })

One thought that came to mind that doesn't sound effecient was to have an operator which checks the condition and throws an error if its loading and simply retrying it after a short delay.

Do you have any better suggestions? I have been looking on delayWhen but seems uneffecient to have a delay like that. I would rather have like a "gate" that opens the stream when loading$ is set to false and the value is emitted as soon as that condition is met.

Thanks in advance!


Solution

  • In this example, the dependent$ observable will emit a value once the source$ observable has emitted false. Please see the working code in: https://stackblitz.com/edit/rxjs-r3yma1?devtoolsheight=33&file=index.ts

    import { of, timer } from "rxjs";
    import { filter, map, switchMap, take, tap } from "rxjs/operators";
    
    const arr = [true, true, true, true, true, true, false];
    const source$ = timer(0, 1000).pipe(
      map(i => arr[i]),
      tap(console.log)
    );
    
    const dependent$ = of("the other guy said false");
    
    source$
      .pipe(
        filter(val => val === false),
        switchMap(() => dependent$),
        take(1)
      )
      .subscribe(console.log);