0

I have a big problem and after hours of reading documents and solution I can't find how I will be able to solve this problem :

Basically I have in my angular guard this :

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
        return this.checkLogin(route);
    }

    checkLogin(route) {
        return this.authService.login().map(response => {
            if (this.authService.isAuth) {
                return this.authService.grants().map(grants => {
                    if (grants.canRead) {
                        return true;
                    }
                })
            }
        });
    }

What I want to do is first to call the service authService.login, and if I'm authentified then I call the authService.grants to check if the user can read this page or not.

As simple as that but I'm not being able to get into the second call I don't know why it's returning an observable.

Jota.Toledo
  • 27,293
  • 11
  • 59
  • 73
Imad El Hitti
  • 917
  • 3
  • 10
  • 23
  • Btw: Whenever you have something like if (x) return true; else return false; please rewrite as simply return x; – Sebastian Jan 23 '18 at 14:33
  • you dont know why its returning an observable? I suppose you are the one who developed the authService API, so you should know what are the return types of the login and grants methods. Please add the methods definition... – Jota.Toledo Jan 23 '18 at 14:33
  • I do, when I say I don't know why it returns an observable I'm not talking about the service but about `return this.checkLogin(route);` if I console log this if I'm auth it return an observable, and if I'm not logged in it return false @Jota.Toledo – Imad El Hitti Jan 23 '18 at 14:35

1 Answers1

2

Without having the definitions of your methods, Ill assume the following:

interface Rights {
   canRead: boolean;
}

class AuthService { 
  grants(): Observable<Rights>{}
  login(): Observable<any>{}
}

The problem is, that currently the return type of your checkLogin method is Observable<boolean>| Observable<Observable<boolean>>. This is because:

  • If this.authService.isAuth is false, the outer map will yield a Observable<boolean>, as you simply return false.
  • If this.authService.isAuth is true, the outer map will yield a Obsevable<Observable<boolean>>, as you will now return the mapped values of another async. operation.

So using that, you should refactor your guard to the following:

import 'rxjs/add/operator/mergeMap'; // can be refactored to pipe + operator
import {of} from 'rxjs/observable/of';

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
        return this.checkLogin(route);
    }

    checkLogin(route): Observable<boolean> {
        return this.authService.login().mergeMap(_=> {
            if (this.authService.isAuth) {
                return this.authService.grants().map(grants => grants.canRead)
            }else{
                return of(false);
            }
        });
    }
}

MergeMap is basically allowing you to concatenate asynchronous operations, and of creates an observable of a sync. value.

Jota.Toledo
  • 27,293
  • 11
  • 59
  • 73