Jacob Stamm
Jacob Stamm

Reputation: 1828

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

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?
  });
}

Upvotes: 2

Views: 5078

Answers (3)

benshabatnoam
benshabatnoam

Reputation: 7632

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

Upvotes: 2

Maksim Romanenko
Maksim Romanenko

Reputation: 365

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')
  );

Upvotes: 0

SoEzPz
SoEzPz

Reputation: 15912

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)));
}

Upvotes: 1

Related Questions