[FIXED] How can I get the value of an API result in Angular subscribe()?

Issue

I need to store some values in local storage after a successful login.

My API returns this

{
  "auth": {
    "name": "FooBar",
    "username: 'foobaz",
  },
  "token": "1234567890abcdefghijklmnop"
}

I’ve tried doing this within login() in authentication.service.ts but I can’t figure it out. I’ve tried (among many other things) using switchMap multiple times inside pipe() with zero success.

authentication.service.ts

login(credentials: { email: any, password: any }): Observable<any> {
  return this.http.post('https://mysite.test/api/login', credentials)
    .pipe(
      map((data: any) => data.token),
      switchMap(token => {
        return from(Preferences.set({ key: 'token', value: token }));
      }),
      tap(_ => {
        this.isAuthenticated.next(true);
      })
    )
}

So I thought I’d try it inside .subscribe() in login.page.ts but I keep receiving errors, like TypeError: undefined is not an object (evaluating 'res.auth.name').

Obviously that exists; I’m using await, plus I’m able to get res.error.message and read the message from the API when there’s an error, so I’m really confused as to what I’m doing wrong?

I thought maybe I need to map() the result again but I just couldn’t get that working. I can’t find examples showing how to do what I want to do.

login.page.ts

async login() {
  const loading = await this.loadingController.create();
  await loading.present();

  this.authService.login(this.myForm.value)
    .subscribe(
      async (res:any) => {

        // THIS IS WHAT I'M TRYING TO ACCOMPLISH
        await Preferences.set({ key: 'authName', value: res.auth.name });
        await Preferences.set({ key: 'authUsername', value: res.auth.username });

        await loading.dismiss();
        this.menu.enable(true);
        this.router.navigateByUrl('/tabs/home', { replaceUrl: true });
      },
      async (res) => {
        await loading.dismiss();
        const alert = await this.alertController.create({
          header: 'Login Failed',
          message: res.error.message,
          buttons: ['OK'],
        });
        await alert.present();
      }
    );
}

Solution

I believe the problem is from the switchMap operator which you have created and returned another new Observable that overwrites the original Observable.

Would suggest performing the Preferences.set action in the tap operator to maintain the original Observable value.

login(credentials: { email: any, password: any }): Observable<any> {
  return this.http.post('https://mysite.test/api/login', credentials)
    .pipe(
      tap((data: any) => {
        Preferences.set({ key: 'token', value: data.token });

        this.isAuthenticated.next(true);
      })
    )
}

Answered By – Yong Shun

Answer Checked By – David Goodson (Easybugfix Volunteer)

Leave a Reply

(*) Required, Your email will not be published