Search code examples
javascriptangularrxjsobservable

RxJS combineLatest add timer to only one observable


I have two entities, Games and Jackpots:
Game interface

{
    id: string,
    name: string
}

Jackpot interface

{
    game: string,
    amount: number
}

First I have two observables, one to get games and one to get jackpots.
And after getting the data i want to merge the data of jackpots into games based on id. And since the jackpots observale should get the data each seconds i used the operator timer to do so. So here's my implementation:

private getGames = (category: string): Observable<IGame[]> => {
        return timer(0, 3000).pipe(
            mergeMap(() => combineLatest([this.gameService.getGames(), this.gameService.getJackpots()])),
            map(([games, jackpots]) => {
                return games?.filter(game => game?.categories?.includes(category))?.map(game => {
                    return { ...game, jackpot: jackpots?.find(jackpot => jackpot?.game === game?.id) };
                })
            })
        );
    };

This implementation works fine and the data is fetched every 3 seconds. Now as you can see both Games and Jackpots observable get fetched every 3 seconds, My question is: is there a way to only run the Jackpots observable every 3 seconds, and exclude the Games observable from that timer.


Solution

  • Context

    combineLatest has two important properties:

    • it emits every time any of the Observables emits a value.
    • it requires all source Observables to emit at least one value.

    Solution

    You can set the timer only for the games Observable and combine it with the jackpots one.

    private getGames = (category: string): Observable<IGame[]> => {
      return combineLatest([
        timer(0, 3000).pipe(mergeMap(() => this.gameService.getGames())),
        this.gameService.getJackpots(),
      ]).pipe(
        map(([games, jackpots]) => {
          return games
            ?.filter((game) => game?.categories?.includes(category))
            ?.map((game) => {
              return { ...game, jackpot: jackpots?.find((jackpot) => jackpot?.game === game?.id) };
            });
        })
      );
    };