RxJs MergeMap and finalize not working as expected (as I thought)

Viewed 812

I am having problems with finalize or complete using the code below. I want to be able to call loading = false after all is done. I tried to use finalize and complete but it is being called too early and multiple times. Any help? Thanks

displayPost(postDetail) {
  //some rendering stuff
  renderHTML(postDetail);
}

// returns a post query object 
getPostQuery(username, postId) {
 query: `{
        post (id:"${username}", postId:"${postId}") {
          id
          title
          content }`
  return query;
}

let loading = true
//getUserHTTP() is an http request
getUserHTTP(userId).pipe(
  switchMap(user => {
    const ids = [];

    // let's say oldest 100 posts
    for (let i = 0; i < 100; i++) {
      ids.push(getPostQuery(user.username, i))
    }

    return from(ids);
  }),
  mergeMap(query => this.httpClient.post(url, query)),
  finalize(() => {
    //this is being called too early and multiple times
    loading = false;
  })
).subscribe({
  next: result => { /* doing staff */ displayPost(result) },
  error: err => { /* handle errors */ },
  complete: () => { /* not working */ }
})

1 Answers

mergeMap would trigger multiple parallel requests with each having it's own stream path. So the finalize would be triggered for each stream. Instead you could use forkJoin to trigger multiple requests in parallel that will only emit after all the individual streams complete.

If you're using toPromise() to convert the HTTP observable to a promise, avoid doing it. It isn't required here. You could also skip the from when using forkJoin.

Try the following

import { forkJoin } from 'rxjs';
import { switchMap, finalize } from 'rxjs/operators';

let loading = true;
getUserHTTP(userId).pipe(
  switchMap(user => {
    const reqs$ = [];
    for (let i = 0; i < 100; i++) {        // let's say oldest 100 posts
      ids.push(
        this.httpClient.post(              // <-- do the HTTP request here
          url,
          getPostQuery(user.username, i)
        )
      );
    }
    return forkJoin(req$);                 // <-- return `forkJoin` here
  }),
  finalize(() => loading = false)
).subscribe({
  next: result => { /* doing stuff */ displayPost(result) },
  error: err => { /* handle errors */ },
  complete: () => { }
});
Related