ufk
ufk

Reputation: 32104

rxjs interval will execute if another 2 observables are true

I'm writing an angular15 app with a youtube player component in it, i'm trying to work with rxjs but i think that i have one issue that i got wrong, the mergeMap. i'm really new to rxjs so sorry for any mistakes

I have 2 subscriptions, one for if youtube library as finished loading, and the other if the youtube player is ready.

first lets look just at the interval:

this.YTSubscription=interval(100).pipe(
      exhaustMap((x, y)=>{
        this.currentTimeSubject.next(this.player.getCurrentTime());
        this.isPlayingSubject.next(this.player.getPlayerState() === YT.PlayerState.PLAYING);
        this.isMutedSubject.next(this.player.isMuted());
        this.volumeSubject.next(this.player.getVolume());
        return of(true);
      }),
    ).subscribe({next: (data )=>{
      },
      error: (err)=> {
        this.YTSubscription?.unsubscribe();
      }
    });

this works fine, it runs in intervals on 100ms and i use exhaustMap to make sure that the next iteration will be executed only if the previous one completed in case when i'll add more calculations it may take more than 100 ms.

next i want in the interval to check if youtube is loaded, for that i have the observable isYouTubeLoaded, so i tried using mergeMap for this.. i guess this is not the right way? but it still worked:

this.YTSubscription=interval(100).pipe(
      mergeMap(x => this.isYouTubeLoaded),
      exhaustMap((x, y)=>{
        if (!x) {
          return of(false);
        }
      ...

now x inside exahustMap contains the isYouTubeLoaded and this does the job.

now i have another observable that i want to check and only if both of them are true to run the interval, if not to wait for the next iteration, this is where i get lost because if i add another mergeMap i can't see both values in exhaustMap.

so from reading some more i assume that i'm not supposed to use mergeMap at all, maybe filter ? but i still have no clue how to do that with 2 observables.

any ideas?

Upvotes: 0

Views: 408

Answers (2)

ufk
ufk

Reputation: 32104

@churill really helped, in the end i need two pipes and not 3 but the implementation is the same, still marking his answer as the correct one, just showing here the resulting code:

 this.YTSubscription=combineLatest([interval(100), this.isYouTubeLoaded]).pipe(
      map(([intr, loaded])=>(loaded)),
      filter((loaded)=> (loaded)),
      exhaustMap(()=>{
        try {
          if (this.player.getPlayerState() === YT.PlayerState.UNSTARTED) {
            return of(false);
          }
        } catch (e) {
          return of(false);
        }
        this.currentTimeSubject.next(this.player.getCurrentTime());
        this.isPlayingSubject.next(this.player.getPlayerState() === YT.PlayerState.PLAYING);
        this.isMutedSubject.next(this.player.isMuted());
        this.volumeSubject.next(this.player.getVolume());
        return of(true);
      }),
    ).subscribe({next: (isUpdated)=>{
      },
      error: (err)=> {
        console.error(err);
      }
    });

Upvotes: 0

Lukas-T
Lukas-T

Reputation: 11340

I'm not entirely sure, what you want to do, but I'll try to answer this part of your question:

now i have another observable that i want to check and only if both of them are true to run the interval, if not to wait for the next iteration, this is where i get lost because if i add another mergeMap i can't see both values in exhaustMap.

combineLatest([src1, src2]).pipe(       // check both
  filter(([ok1, ok2]) => ok1 && ok2),   // only if both are true
  switchMap(() => timer(...)            // run the timer
).subscribe(...);

Upvotes: 1

Related Questions