Home > OS >  How can I subscribe to two different observables that come from paramMap?
How can I subscribe to two different observables that come from paramMap?

Time:10-28

When I am requesting data using route params paramMap I'm able to get everything working great when it's a single argument. For example, foo.getThing(id).

I am struggling how to "observe" multiple arguments though. I need both, my organizationId and my locationId to look up a location.

I've been reading through several tutorials and perhaps ForkJoin may be what I need, but all I have seen so far is getting the initial request from something that doesn't take arguments. For example, foo.getStuff() not foo.getThing(id)

// settings.component.ts

private organizationId!: string;
private locationId!: string;

private organizationId$ = this.activatedRoute.paramMap.pipe(
    tap((params) => {
        this.organizationId = params.get('organizationId')!;
    })
);

private locationId$ = this.activatedRoute.paramMap.pipe(
    tap((params) => {
        this.locationId = params.get('locationId')!;
    })
);

public location$: Observable<ILocation> = this.locationId$.pipe(
    switchMap(() =>
        this.locationService.getLocation(this.organizationId, this.locationId)
    )
);

When I am getting details about my organization, I can just subscribe to the organizationId. If that changes, the response updates accordingly.

I am trying to accomplish the same for my location. If the organizationId or locationId change, I'd like the pipe to re-run and get the correct data.

How can I subscribe to two different observables?

CodePudding user response:

My good!! "make it simple, make it easy" (*)

//if we want to store the params in this.organizationID and this.locationId 
location$=this.activatedRoute.paramMap.pipe(
          switchMap(params=>{
             this.organizationId = params.get('organizationId')!
             this.locationId = params.get('locationId')!
             return this.locationService.getLocation(this.organizationId, this.locationId)
          }))

Or

//if we needn't store the params
location$=this.activatedRoute.paramMap.pipe(
          switchMap(params=>{
             const organizationId = params.get('organizationId')!
             const locationId = params.get('locationId')!
             return this.locationService.getLocation(organizationId, locationId)
          }))

(*) Why all the another answers are so complex?

CodePudding user response:

What you are looking for is probably combineLatest. Adding distinctUntilChanged because it should fit your case

private organizationId$ = this.activatedRoute.paramMap.pipe(
    map((params) => params.get('organizationId')),
    distinctUntilChanged()
);

private locationId$ = this.activatedRoute.paramMap.pipe(
    map((params) => params.get('locationId')),
    distinctUntilChanged()
);

private whatYouNeed$ = combineLatest(this.organizationId$, this.locationId$)

One way to get the values is this for example

this.whatYouNeed$.subscribe(([organizationId, locationId]) => console.log(organizationId, locationId))

CodePudding user response:

combineLatestWith is an operator combines the source with provided observables to emit an array of each observable's latest values each time any of them changes. So you'd want to change your location$ definition to:

const location$ = locationId$.pipe(
  combineLatestWith(organizationId$),
  switchMap(
    ([locId, orgId]) =>
    this.locationService.getLocation(
      locId,
      orgId
    )
  )
);

CodePudding user response:

The question is not "How can I subscribe to two different observables?", but rather, "How can I create an observable from multiple sources, that emits whenever any of the sources emit".

ginalx is right, combineLatest will help you with this:

  private organizationId$ = this.activatedRoute.paramMap.pipe(
    map(params => params.get('organizationId')),
    distinctUntilChanged()
  );

  private locationId$ = this.activatedRoute.paramMap.pipe(
    map(params => params.get('locationId')),
    distinctUntilChanged()
  );

  public location$ = combineLatest([this.organizationId$, this.locationId$]).pipe(
    switchMap(([orgId, locId]) => this.locationService.getLocation(orgId, locId))
  );

However, if your only sources both come the route params, it may be simpler to use params instead of paramMap since you have access to the full params object (not just a single value):

  public location$ = this.activatedRoute.params.pipe(
    switchMap(params => this.locationService.getLocation(params.organizationId, params.locationId))
  );
  • Related