-1

Having two models look like this:

export class Game {
 id: number;
 name: string;
 platform: number;
}

export class Platform {
 id: number;
 name: string;
}

having an observable array of the Game object that has a property of platformId which is related to the Platform object. for better understand, I created two separate methods for getting a list of my games and another method for getting a platform based on id.

getGames(): Observable<Game[]> {
    return of([
      {
        id: 1,
        name: 'god of war',
        platform: 1,
      },
      {
        id: 2,
        name: 'halo',
        platform: 2,
      },
    ]);
  }

  getPlatform(id): Observable<Platform> {
    if (id === 1)
      return of({
        id: 1,
        name: 'ps4',
      });

    if (id === 2)
      return of({
        id: 2,
        name: 'xbox',
      });
  }

now I'm with help of two operators of rxjs (switchMap,forkJoin) reach to this point:

this.getGames()
      .pipe(
        switchMap((games: Game[]) =>
          forkJoin(
            games.map((game) =>
              forkJoin([this.getPlatform(game.platform)]).pipe(
                map(([platform]) => ({
                  game: game.name,
                  platform: platform.name,
                }))
              )
            )
          )
        )
      )
      .subscribe((v) => {
        console.log(v);
        this.gamesV2 = v;
      });

and my final result:

 [
     {
      game: "god of war"
      platform: "ps4"
     },
     {
      game: "halo"
      platform: "xbox"
     }
 ]

is it possible to achieve this in a simpler way? StackBlitz

FarbodKain
  • 229
  • 3
  • 15

2 Answers2

1

By flattening an inner observable array of getPlatformV2:

this.getGames()
  .pipe(
    switchMap(games =>
      combineLatest(
        games.map(game =>
          this.getPlatformV2(game.id).pipe(
            map(platform => ({
              game: game.name,
              platform
            }))
          )
        )
      )
    )
  )

Extra: Regarding Game and Platform, you should use TS types or interfaces instead of classes if you won't implement a constructor on those.

0

I find another way in StackOverflow thanks to Daniel Gimenez and putting it here, if anyone has better and simpler, I really appreciate it to share it with me. Create another method which returns the name of the platform:

 getPlatformV2(id): Observable<string> {
    const platforms = [
      {
        id: 1,
        name: 'ps4',
      },
      {
        id: 2,
        name: 'xbox',
      },
    ];
    return of(platforms.find(x=>x.id===id).name);
  }
}

and instead of using two forkjoin, I used concatMap

this.getGames()
      .pipe(
        switchMap((games) => games),
        concatMap((game) =>
          forkJoin({
            game: of(game.name),
            platform: this.getPlatformV2(game.platform),
          })
        ),
        toArray()
      )
      .subscribe(console.log);
FarbodKain
  • 229
  • 3
  • 15