Damon
Damon

Reputation: 4484

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

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?

Upvotes: 0

Views: 354

Answers (4)

ginalx
ginalx

Reputation: 2247

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

Upvotes: 1

Eliseo
Eliseo

Reputation: 57909

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?

Upvotes: 3

BizzyBob
BizzyBob

Reputation: 14740

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

Upvotes: 1

JSmart523
JSmart523

Reputation: 2497

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

Upvotes: 1

Related Questions