Mike Sav
Mike Sav

Reputation: 15321

Angular & RxJS - Combining Multiple XHR Service calls using .mergeMap

I recently asked a question to prevent a pyramid of doom and got a great answer however as my system advances I need to amend my code and my implementation isn't working.

In my system I subscribe to an Angular Material Dialog afterClose action, I take the result, filter that result, then I call a service that retrieves data (using REST / XHR). When this is resolved I take and modify some of the returned data and return another service method. mergeMap is used to prevent a series of nested .subscribes

dialogRef
.afterClosed()
.filter((result) => typeof result === 'string')
.mergeMap((result) => this.myService.getuser(this.id).mergeMap((user: User) => {
  const mergedObj = Object.assign({}, user, {LifeEventDate: this.dateService.convertToCorrectFormat(result)});
  return this.myService.updateUser(this.id, mergedObj);
}))
.do(() => {
  // run some actions in the Component...
})
.subscribe();

Now I wish to take some of the returned data from this.myService.getuser and call the same service but another method this.myService.logSomething (which also makes a REST / XHR call). The method this.myService.logSomething doesn't return any necessary data, when complete it just returns an object {success: true} although it may be prudent to introduce a .catch incase of errors. I'd like to add it to the code above, placing it within the second mergeMap doesn't work as when looking in the Chrome Dev tools no network request is made for this. For example...

dialogRef
.afterClosed()
.filter((result) => typeof result === 'string')
.mergeMap((result) => this.myService.getuser(this.id).mergeMap((user: User) => {

  /* NEW CODE */
  // I need to take some of the data returned from the returned user above
  this.myService.logSomething({user:user.id, something: user.something, somethingElse: user.somethingElse});

  const mergedObj = Object.assign({}, user, {LifeEventDate: this.dateService.convertToCorrectFormat(result)});
  return this.myService.updateUser(this.id, mergedObj);
}))
.do(() => {
  // run some actions in the Component...
})
.subscribe();

I am unsure where or how to place this new service call. Both service methods nested in the first .mergeMap require data from the first service call, how can I add a third service call to my code?

Sorry if the question is badly structured, makes no sense or is unclear please let me know and I'll rephrase.

Upvotes: 2

Views: 1154

Answers (2)

martin
martin

Reputation: 96969

I think you could chain multiple mergeMap (or concatMap) calls and map the result to the original user object (I'm assuming that logSomething() returns an Observable):

dialogRef
  .afterClosed()
  .filter(...)
  .mergeMap((result) => this.myService.getuser(this.id))
  .mergeMap(user => this.myService
    .logSomething(...)
    .map(() => user)) // !!!
  )
  .mergeMap(user => this.myService.updateUser(...))
  .do(() => ...)
  .subscribe();

Upvotes: 1

BeetleJuice
BeetleJuice

Reputation: 40936

Why are you using mergeMap? I would try something like this:

dialogRef.afterClosed().filter(...)
    .switchMap(e => this.mysService.getUser(this.id))
    .switchMap(user => Observable.forkJoin(
        this.myService.logSomething(user),
        (user) => {
            const mergedObj = Object.assign();
            return this.myService.updateUser(this.id, mergedObj)
        },
        (a,b) => b //Selector: return a to pass along the first observable's result
    ))
    .do(...)
    .subscribe(...)

Upvotes: 0

Related Questions