How to extract result inside subscribe block while using two concatmap inside pipe in rxjs Angular

136 Views Asked by At

I have a code like following:

this.security.isLoggedIn$
        .pipe(
            distinctUntilChanged(),
            switchMap(
                (isLoggedInApp: boolean) =>
                    isLoggedInApp
                        ? of(true).pipe(
                                concatMap(() => this.security.getUser()),
                                concatMap(( partyId ) => this.loginService.getLendingType(partyId))
                        )
                        : of(false).pipe(finalize(() => this.router.navigateByUrl('login'))) //// TODO: needs refactoring, investigate routing
            )
        )
        .subscribe((result) => {
            console.log(result);
            //this log prints {"lendingType": "LendingPartner","partyId": "64f9f398-3a79-48d6-b4b7-89d41ccedb3b"}
        });

in the above code my problem is, I want to access the result of the call getLendingType(partyId). Here is my code for getLendingType(partyId)

  public getLendingType(partyId: string): Observable<{ lendingType: string, partyId: string }> {
return this.customerService.getCustomer(partyId).pipe(
    map((customer: ICustomer) => {
      return { lendingType: customer.LendingType, partyId: partyId } ;
    })
  );
}

So the getLendingType returning me two value. So here problem is, I cannot access these two values inside subscribe block. However, when I am returning only one value for example just lendingType I can able to access it inside subscribe block. To be specific, I am actually getting those two value inside the subscribe block as you can see in log prints. However I dont know how to access them. If I hover over the result in my visual code it shows me the result consist of one boolean and one object like the following image.

enter image description here

I have tried result.lendingType or result['lendingType'] which throwing me compiler error as result is a complex object like the image shown. In this case what is the way to access this two value.

Thank you in advance.

2

There are 2 best solutions below

2
On BEST ANSWER

The pipe that you've created returns LendingData if the user is logged in, and a boolean (false), when the user is not logged in. This is why when you try to access result.lendingType or result['lendingType'] on the failing case (!isLoggedInApp), you're code tries todo: false.lendingType. This is incorrect, hence why an error is being thrown.

If you're ever confused by a pipe that you've written, I suggestion that you simplify it by breaking it apart. This is good practice, and your colleagues will thank you later. In this case, deal with the LendingData and navigation in two different pipes.

/* ----------------- Deal with lending data ---------------- */

private getLendingData$ = this.security.getUser().pipe(
  switchMap((partyId) => this.loginService.getLendingType(partyId))
);

public lendingData$ = this.security.isLoggedIn$.pipe(
  distinctUntilChanged(),
  // if the user is logged in, return their lending data, else return null
  switchMap(isLoggedIn => iif(() => isLoggedIn, getLendingData$, of(null)),
  // so you don't make the API call more than once
  // for multiple subscribers
  shareReplay(1)
);

lendingData$.subscribe((result) => {
  // can return LendingData or null, therefore, access data with ?.
  // Ie) result?.lendingType
  console.log(result);
  // this log prints
  // { 
  //    "lendingType": "LendingPartner",
  //    "partyId": "64f9f398-3a79-48d6-b4b7-89d41ccedb3b"
  // }
});

/* ----------------- Deal with navigation ---------------- */

this.security.isLoggedIn$.pipe(
  distinctUntilChanged(),
  filter(isLoggedIn => !isLoggedIn)
).subscribe(() => {
  this.router.navigateByUrl('login'));
});

0
On

You could build in a type check like that:

if (typeof result !== "boolean"){
    console.log(result.lendingType)
}

Typescript is now smart enough to know that result can no longer be of type boolean.