Reputation: 55
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
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
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
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