angularangular8angular-routingauth-guardangular-guards

Hide the navbar in angular 8 (auth-guard routes are not recorded in routes.event)


All,

Before implementing the auth guard, I was able to hide my Navbar from login and registration screen. By reading the route events in component.ts and hiding the nav-bar by ngIf. After I implemented the auth guard the route made by auth guard to login page is not hiding the nav bar below is my code..

Here my auth guard service will check whether user is authenticated or not from auth service(Which will get data from cognito). Now, how can I hide the nav bar from routes happening from auth guard. Please help

app.component.html

<app-toolbar *ngIf="isShowNavbar"   ></app-toolbar>

<router-outlet></router-outlet>

app.component.ts

import { Component,OnInit } from '@angular/core';
import {AuthorizationService} from "./authorization.service";
import { Router, ActivatedRoute, UrlSegment, NavigationEnd } from '@angular/router';
import { Observable } from 'rxjs';
import { first, distinctUntilChanged, throttleTime } from '../../node_modules/rxjs/operators';
@Component({
  // tslint:disable-next-line: component-selector
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit  {

  isLoggedIn$: Observable<boolean>;
  isShowNavbar: boolean;
  constructor(private auth: AuthorizationService,private router: Router) {}
  ngOnInit() {
    this.isLoggedIn$ = this.auth.IsLoggedIn;
    this.router.events.pipe(throttleTime(100), distinctUntilChanged()).subscribe((navEnd: NavigationEnd) => {
      console.log(navEnd.url)
      if (navEnd) {
        if (navEnd.url === "/login" || navEnd.url ==="/register" ) {
          this.isShowNavbar = false
        } else {
          this.isShowNavbar = true;
        }
      }
    });
  }}

route.ts

const routes: Routes = [
  {path: '', redirectTo: '/cards', pathMatch: 'full',canActivate :  [ AuthGuardService ] },
  { path: 'shareditems', component: ShareditemsComponent,canActivate :  [ AuthGuardService ] },
  { path: 'home', component: AppCardsComponent,canActivate :  [ AuthGuardService ]  },
  { path: 'calendar', component: CalendarComponent,canActivate :  [ AuthGuardService ] },
  {path: 'lan', component: LanComponent,canActivate :  [ AuthGuardService ] },
  {path:'login', component:LoginComponent},
  {path: 'register', component:RegisterComponent },
  {path:'nav', component:CommonComponent,canActivate :  [ AuthGuardService ] }

];

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

auth.guard service:

canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean>
{ 
    return this.auth.isAuthenticated() 
      .then(data => { 
          return Promise.resolve(true); 
        }).catch(err => { 
           this._router.navigate(['/login']); 
           return Promise.resolve(false); 
        }); 
       } 
}

Solution

  • Instead of showing or hiding your toolbar based on the current URL, I would instead structure your routes and use layout components.

    authenticated-layout.component.html

    <app-toolbar></app-toolbar>
    <router-outlet></router-outlet>
    

    anonymous-layout.component.html

    <router-outlet></router-outlet>
    

    You can inherit these layouts (and the auth guard) by using route children.

    route.ts

    const routes: Routes = [
      { path: '', component: AuthenticatedLayoutComponent, canActivate : [ AuthGuardService ], 
        children: [
        { path: '', redirectTo: '/cards', pathMatch: 'full' },
        { path: 'shareditems', component: ShareditemsComponent },
        { path: 'home', component: AppCardsComponent },
        { path: 'calendar', component: CalendarComponent },
        { path: 'lan', component: LanComponent },  
        { path:'nav', component: CommonComponent }
      ] },
      { path: '', component: AnonymousLayoutComponent, children: [
        { path:'login', component: LoginComponent},
        { path: 'register', component: RegisterComponent },
      ] }
    ];
    
    @NgModule({
      imports: [RouterModule.forRoot(routes)],
      exports: [RouterModule]
    })
    export class AppRoutingModule { }
    

    DEMO: https://stackblitz.com/edit/angular-jzmw3d

    Alternative

    Ultimately, your logic is that you only want to show the navbar when the user is logged in. You can set the visibility via a subscription to your auth service.

    app.component.ts

    export class AppComponent implements OnInit  {
    
      isLoggedIn$: Observable<boolean>;
      isShowNavbar: boolean;
    
      constructor(private auth: AuthorizationService,private router: Router) {}
    
      private destroyed$ = new Subject();
    
      ngOnInit() {
        this.isLoggedIn$ = this.auth.IsLoggedIn;
        this.isLoggedIn$.pipe(
          takeUntil(this.destroyed$)
        ).subscribe(isLoggedIn => {
          this.isShowNavbar = isLoggedIn;
        });
      }
    
      ngOnDestroy() {
        this.destroyed$.next();
        this.destroyed$.complete();
      }
    }
    

    I would still recommend using child routes with a single auth guard in the parent though.

    Also, I recommend returning the UrlTree from canActivate if you want to instruct the router to navigate to a new route.

    auth-guard.service.ts

    canActivate (next: ActivatedRouteSnapshot, state: RouterStateSnapshot
    ): Promise<boolean | UrlTree> { 
      return this.auth.isAuthenticated() 
        .then(data => { 
          return Promise.resolve(true); 
        }).catch(err => { 
          const urlTree = this._router.parseUrl('/login');
          return Promise.resolve(urlTree); 
        }); 
      };
    }