0
votes

Not sure how to return a value from an Observable to CanActivate
for navigation to continue.

I have a CanActivate implementation that makes an http request to my server.
It places the result in a Subject
depending upon certain conditions (if)
where it can be picked up and returned to CanActivate
to continue navigation.

But when the thing runs,
I can't seem to figure out how to get to the
boolean value that comes from that subscription.

private isAdminSubj: Subject<boolean> = new Subject<boolean>();
private isAdmin: Observable<boolean> = this.isAdminSubj.asObservable();
private go:boolean = false;

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean{

        /* to store and redirect after login if user not logged in */
    let target_url: string = state.url;

    this.verifyLoginForAdmin( target_url );

     this.isAdminSubj.subscribe(user_authorized => { this.go = user_authorized;} );

     return this.go;

}

verifyLoginForAdmin( target_url: string ){

    if( this.authService.isLoggedin() ){

        let token_email = 
            this.authService
                .jwt_helper
                .decodeToken( localStorage.getItem( this.authService.jwt_name ) ).email;

        this.authService.isAdmin( token_email )
            .subscribe({ 
                next:  data => {
                if( data )
                    this.isAdminSubj.next(true)
                    else{
                        this.router.navigate( [ '/coding-blog' ]);
                        this.isAdminSubj.next(false);
                    }
                },
                error: error => console.log("CanActivate Error-->", error),
                complete: () => console.log("complete")
            })

        }else

    this.authService.targetUrl = target_url;

    this.router.navigate( [ '/projects' ] );

    this.isAdminSubj.next(false);


}

}

authService#isAdmin() is:

isAdmin( email: string ): Observable<boolean>{

    return this.getDbInfo
        .getOneUserByEmail( email )
        .map( res => res.json().data.admin );

}

I also tried CanActivate():Observable<boolean> but where to subscribe and get to the value:

private isAdminSubj: Subject<boolean> = new Subject<boolean>();
private isAdmin: Observable<boolean> = this.isAdminSubj.asObservable();

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean>{

        /* to store and redirect after login if user not logged in */
    let target_url: string = state.url;

    this.verifyLoginForAdmin( target_url );

    return this.isAdmin;

}
2

2 Answers

1
votes

You don't have to immediately return a boolean from canActivate, you can also return an Observable or a Promise.

https://angular.io/docs/ts/latest/api/router/index/CanActivate-interface.html

interface CanActivate {
    canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) : Observable<boolean>|Promise<boolean>|boolean
}

So return a boolean if you know the answer right away and an Observable<boolean> in case you need to call your service/Http to determine the answer.

0
votes

Turns out you can't have any logic within the CanActivate guard as I was trying in the above post.

The valid form is:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean>{

    let target_url: string = state.url;

    return this.verifyLoginForAdmin( target_url );

}  

Where this.vefityLoginForAdmin( target_url );
must return an observable after the logic has already been implemented.

Thanx!