Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use tap() instead of map() RxJS and Angular

I have a login guard which basically check if the user il logged in. If he is logged, it skips the login and go to home page. I wrote this code, and this works:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
    return this.store.select(fromApp.isAuthenticated)
        .pipe(take(1),
            map(isAuthenticated => {
                if (isAuthenticated) {
                    this.router.navigate(['/home']);
                    return false;
                } else {
                    return true;
                }
            })
        )
}

Now, since I don't have to change or edit the output data (isAuthenticated boolean), I thought: well, why don't use tap operator? So, I re-write my code:

canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
    return this.store.select(fromApp.isAuthenticated)
        .pipe(take(1),
   HERE------> tap(isAuthenticated => {   <------ HERE
                if (isAuthenticated) {
                    this.router.navigate(['/home']);
                    return false;
                } else {
                    return true;
                }
            })
        )
}

Then I went to Chrome, and I saw black page and this was the case:

  • I open the app
  • I'm not logged in
  • The url becomes http://localhost:4200/#/ instead of http://localhost:4200/#/login, result: blank page
  • If I try to go manually in http://localhost:4200/#/login, it stays in that page but I see a blank page
  • If I try to go home, it redirects on http://localhost:4200/#/ instead of http://localhost:4200/#/login

In any case, I see blank page. So, I went in debug and I noticed that it correctly jump inside the if/else block... so, why tap() is breaking the app?

like image 591
panagulis72 Avatar asked Dec 17 '22 22:12

panagulis72


2 Answers

This is the signature of canActivate:

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

canActivate must either return boolean or Promise. Therefore you must map it and return a boolean or Promise. tap will not do the trick.

like image 90
siva636 Avatar answered Dec 28 '22 10:12

siva636


The guard canActivate has to return an Observable<boolean> in order for the Angular guard mechanism to work.

Using map allows you to define a return which is different from what you get from isAuthenticated, and this probably explains what you see.

In your first version canActivate acutally returns an Observable<boolean> - in the second case it returns this this.store.select(fromApp.isAuthenticated).pipe(take(1)) , and probably it is not what you want.

like image 33
Picci Avatar answered Dec 28 '22 09:12

Picci