Search code examples
angularrxjsobservableguard

angular 6 guard Observable hanging


first i have created 2 guards one check if user signin if not navigated hie to login route

this is code

    import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs';
import { AuthenticationService } from '../auth/authentication.service';
import { Router } from '@angular/router';
import { tap, map, take } from 'rxjs/operators';
import {of} from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class IsUserGuard implements CanActivate {
  constructor( private auth:AuthenticationService, private router:Router){}

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {

    return this.auth.user$.pipe(
      take(1),
      map(user => !!user),
      tap(isAuthenticated => {
          if(!isAuthenticated){
            console.log('must login');
            this.router.navigate(['/login']);
          }
      })
    )


  }
}

so , it's working great but the issue here in the second guard i check if user signin he don't allowed to browse login route again so i create this guard

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs';
import { Router } from '@angular/router';
import { AuthenticationService } from '../auth/authentication.service';
import { tap, take, map, } from 'rxjs/operators';
import { of } from 'rxjs';
@Injectable({
  providedIn: 'root'
})
export class IsGuestGuard implements CanActivate {
  constructor(private router:Router, private auth:AuthenticationService){}
  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
      return this.auth.user$.pipe(
        take(1),
        map(user => !!user),
        tap(isAuthenticated => {

        if(isAuthenticated){
          console.log('not a allow')
          this.router.navigate(['']);
        }
        else{
          console.log('allowe to show')
          return true
         //return of(true) give me the same resault
        }
        }),
      )
  }
}

it's working and console printed 'allowe to show' but the page doesn't appear so i feel i'm in loop don't stop , if I return true instead my code in second guard the page working

this is a routes code also

    const routes: Routes = [
    {
        path: '',
        component: PagesComponent,
        canActivate:[IsUserGuard],
        children: [
            {
                path: '',
                loadChildren: './components/dashboard/dashboard.module#DashboardModule'
            },
        ]
    },
    {
        path: 'login',
        canActivate: [IsGuestGuard],
        loadChildren: './auth/auth.module#AuthModule',
    },
    {
        path: '404',
        component: ErrorPageComponent
    },
    {
        path: 'error/:type',
        component: ErrorPageComponent
    },
];

this code is working after help guys @JeffFairley @fan-cheung , thanks guys

export class IsGuestGuard implements CanActivate {
  constructor(private router:Router, private auth:AuthenticationService){}
  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {

      return this.auth.user$.pipe(
        map(isAuthenticated => {

          if(isAuthenticated){
            this.router.navigate(['/']);
            return false
          }

            return true
        })
      )

  }
}

Solution

  • The boolean is already returned by map(user=>!!user), tap is a side effect operator. Try replace tap with map() and return correct value see if it's working.

     canActivate(
        next: ActivatedRouteSnapshot,
        state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
          return this.auth.user$.pipe(
            take(1),
            map(user => !!user),
            map(isAuthenticated => {
    
            if(isAuthenticated){
              console.log('not a allow')
              this.router.navigate(['']);
                return false
            }
    
              console.log('allowe to show')
              return true
             //return of(true) give me the same resault
    
            }),
          )
      }