brandudno
brandudno

Reputation: 55

Angular/RXJS nested observables using the response from the first call in the second two calls

I have a POST request to create a Movie that returns an Observable, the result of this request returns me an ID that I need to make two further requests using this ID to add a Director & Movie Images.

I have the following call, it works perfectly when it comes to adding the Director however when I get to the second flatMap I'm unable to loop through the images to POST them without adding a subscribe on the end.

Is there a better way to do this? I have tried switchMap, mergeMap and map but I cannot get the second request to fire without the subscribe.

this.Movie.createMovie(movie).pipe(
      map((movie: Movie) => {
        return movie;
      }),
      switchMap((movie: Movie) => this.movieRepository.postDirector(director, movie.id)),
      flatMap((director: Director) => {
        return movieImages.map((image) => {
          return this.movieRepository.addMovieImage(image, director.movie_id).subscribe()
        });
      })
    ).subscribe({
      next: (response: any) => {
        console.log(response)
      }
    })

Upvotes: 2

Views: 763

Answers (3)

yaircarreno
yaircarreno

Reputation: 4267

Great question;

Maybe what you need is to properly orchestrate the operations, for which you can use Tuples(pair) and a more ordered code like this:

this.Movie.createMovie(movie)
  .pipe(
    concatMap(movie => this.movieRepository.postDirector(director, movie.id).pipe(map(director => [movie, director]))),
    concatMap(pair => this.movieRepository.addMovieImage((pair[0] as Movie).image, (pair[1] as Director).movie_id))
  )
  .subscribe(response => console.log(response));

You can also use switchMap instead of a concatMap. If you need more information on how to orchestrate operations, I recommend the following article: Clean the operators's chain in RxJS.

Greetings, I hope I have helped.

Upvotes: 0

Naveen Motwani - AIS
Naveen Motwani - AIS

Reputation: 619

Assuming you want to save director and the image and both calls must be finished before I save another movie, I would have approached it this way

 this.Movie.createMovie(movie).pipe(
    concatMap((movie: Movie) => {
      const saveDirectory$ = this.movieRepository.postDirector(director, movie.id);
      const saveMovieImage$ = this.movieRepository.addMovieImage(image, director.movie_id);

     return forkJoin(saveDirectory$, saveMovieImage$).pipe(map(([directoryAPIresponse, imageApiResponse])=>{
       // you can check if the both records created based on your api response;
       return of(true);
     }));
    )).subscribe({
      next: (response: any) => {
        console.log(response)
      }
    })

The reason I use concatMap because I want to wait for inner apis to complete before I make another call.

forkJoin: I want both inner APIs to complete.

Upvotes: 1

Fan Cheung
Fan Cheung

Reputation: 11380

Convert your array to an array of observable and run them in forkJoin

flatMap((director: Director) => {
    return forkJoin(movieImages.map((image) => {
      return this.movieRepository.addMovieImage(image, director.movie_id)
    }));
})

Upvotes: 0

Related Questions