How do I create a resolver with multiple requests dependent on data from a prior request?

Viewed 3737

I have a component which retrieves its business object from a single HTTP request, and then has several subsequent requests to populate drop-down lists. The arguments in those subsequent requests consist of data from the business object, so those requests can not begin until the first one completes.

Given an example resolver PersonResolver, this is the flow I want to achieve:

  1. Call this.personService.getPersonData(). Returns type Observable<PersonModel>.
  2. Use the returned PersonModel instance, which we'll call personData, to call this.personService.getAdditionalData1(personData.foo) and this.personService.getAdditionalData2(personData.bar). Both return type any[].
  3. Return type Observable<PersonModel, any[], any[]> from the resolve method.

I would like to implement this into the component's resolver, but I am having a tough time wrapping my head around the correct usage of RxJS I need for the job.

Here's what I've got so far. I got stuck pretty quick.

constructor(private personService: PersonService) { }

resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<PersonModel, any[], any[]> | Observable<Observable<PersonModel, any[], any[]>> | Promise<Observable<PersonModel, any[], any[]>> {
  this.personService.getPersonData().subscribe(personData => {
      // what to put in here?
  });
}
3 Answers

First you need to use mergeMap in order to pass the model PersonModel from first call. Then you need to use zip to get all of the result together in one array.

    this.personService.getPersonData.pipe(
      mergeMap(
        personData => zip(
          of(personData),
          of(getAdditionalData1(personData.foo)),
          of(getAdditionalData2(personData.bar))
        )
      )
    ).subscribe(allData => {
      // here you will have all of the data placed in 'allData' param
    });

See this simple StackBlitz DEMO to see this in action

Try something like this...

Note: READ THIS

constructor(private personService: PersonService) { }

resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<PersonModel, any[], any[]> | Observable<Observable<PersonModel, any[], any[]>> | Promise<Observable<PersonModel, any[], any[]>> {
  return this.personService.getPersonData().pipe(
    mergeMap(personData => this.personService.getAdditionalData1(personData.foo)),
    mergeMap(this.personService.getAdditionalData2(personData.bar)));
}

Yet another version

this.personService
  .getPersonData()
  .pipe(
    mergeMap(personData =>
      merge(
        this.personService.getAdditionalData1(personData.foo),
        this.personService.getAdditionalData2(personData.bar)
      )
    )
  )
  .subscribe(
    r => console.log('Response', r),
    e => console.log(e),
    () => console.log('Done')
  );
Related