Angular CanLoad Guard Example
August 31, 2021
This page will walk through Angular CanLoad
route guard example. The CanLoad
guard is used to decide if a module configured with loadChildren
property can be loaded or not. The CanLoad
is an interface with canLoad
method. To use CanLoad
guard, we need to create a service by implementing CanLoad
interface and override its canLoad
method. Then that service is configured with canLoad
property in route configuration. When canLoad
method of our service returns true
then the feature module protected by canLoad
will be lazy loaded otherwise it will not be loaded. CanLoad
takes precedence on preloading and preloading is blocked by CanLoad
guard. Modules protected by CanLoad
has no effect of preloading configuration.
Here on this page we will protect a feature module using
CanLoad
guard and allow to load it only after user authentication. We will also provide example for how to use CanLoad
and CanActivate
guard together.
Contents
Technologies Used
Find the technologies being used in our example.1. Angular 12.1.0
2. Node.js 12.14.1
3. NPM 7.20.3
CanLoad
CanLoad
is a route guard to decide if a module can be loaded configured with loadChildren
property. loadChildren
property is a reference to lazy loaded child routes. If a feature module is protected with CanLoad
and also it is configured for preloading then CanLoad
has precedence over preloading and that feature module will not be preloaded.
Find the structure of
CanLoad
from Angular doc.
interface CanLoad { canLoad(route: Route): Observable<boolean> | Promise<boolean> | boolean }
CanLoad
interface and override canLoad
method. Now using canLoad
property we guard loading of modules. When Angular try to access a module protected by CanLoad
either by preloading or lazy loading, then canLoad
method of our service will run. If canLoad
method of our service returns true
then that module will start loading otherwise it will not be loaded. To achieve can load we can also use a function with canLoad
method signature.
Steps to use CanLoad Guard
Find the steps to useCanLoad
route guard.
Step-1: Create a service implementing
CanLoad
interface and override canLoad
method. Here we will protect module loading for unauthenticated user. We are creating a service AuthGuardService
as following.
auth-guard.service.ts
import { Injectable } from '@angular/core'; import { CanLoad, CanActivate, Route, Router } from '@angular/router'; import { AuthService } from './authentication/services/auth.service'; @Injectable() export class AuthGuardService implements CanLoad { constructor(private authService: AuthService, private router: Router) { } canLoad(route: Route): boolean { const url: string = route.path; console.log('Url:'+ url); if (this.authService.isUserLoggedIn()) { return true; } this.authService.setRedirectUrl(url); this.router.navigate([ this.authService.getLoginUrl() ]); return false; } }
canLoad
method will return true
in the above code and protected module will be applicable to be loaded by lazy loading. If user is not logged-in, then user will be redirected to login page and canLoad
method will return false
and protected module will not be loaded even by preloading.
Step-2: Configure
AuthGuardService
with canLoad
property in route configuration as following in application routing module.
{ path: 'admin', loadChildren: () => import('./admin/admin.module').then(mod => mod.AdminModule), canLoad: [ AuthGuardService ] }
app-routing.module.ts
import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { PreloadAllModules } from '@angular/router'; import { WelcomeComponent } from './welcome.component'; import { DashboardLayoutComponent } from './dashboard.layout.component'; import { PageNotFoundComponent } from './page-not-found.component'; import { AuthGuardService } from './auth-guard.service'; const routes: Routes = [ { path: '', redirectTo: '/welcome', pathMatch: 'full' }, { path: '', component: DashboardLayoutComponent, children: [ { path: 'address', loadChildren: () => import('./address/address.module').then(mod => mod.AddressModule) }, { path: 'admin', loadChildren: () => import('./admin/admin.module').then(mod => mod.AdminModule), canLoad: [ AuthGuardService ] }, { path: 'welcome', component: WelcomeComponent }, { path: '**', component: PageNotFoundComponent } ] } ]; @NgModule({ imports: [ RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules }) ], exports: [ RouterModule ], providers: [ AuthGuardService ] }) export class AppRoutingModule { }
AuthGuardService
in providers
metadata as following.
@NgModule({ providers: [ AuthGuardService ], ------ }) export class AppRoutingModule { }
CanLoad
route guard. In our route configuration we have configured PreloadAllModules
strategy for modules preloading. When the application starts, we will see that AddressModule
will be preloaded but AdminModule
will not be preloaded because it is protected by CanLoad
route guard. When we try to access admin feature, we will be redirected to login page and once we are successfully logged-in, then AdminModule
will start loading. If user is logged-out, still user can access the admin feature because AdminModule
is already loaded.
CanLoad with CanActivate
CanLoad
protects a module to be loaded but once module is loaded then CanLoad
guard will do nothing. Suppose we have protected a module loading using CanLoad
guard for unauthenticated user. When user is logged-in then that module will be applicable to be loaded and we will be able to navigate children paths configured by that module. But when user is logged-out, still user will be able to navigate those children paths because module is already loaded. In this case if we want to protect children paths from unauthorized users, we also need to use CanActivate
guard. As we have already created a service AuthGuardService
for CanLoad
, we will also add code for CanActivate
in it. Find the AuthGuardService
class.
auth-guard.service.ts
import { Injectable } from '@angular/core'; import { CanLoad, CanActivate, Route, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; import { AuthService } from './authentication/services/auth.service'; @Injectable() export class AuthGuardService implements CanLoad, CanActivate { constructor(private authService: AuthService, private router: Router) { } canLoad(route: Route): boolean { const url = route.path; console.log('Url:' + url); if (this.authService.isUserLoggedIn()) { return true; } this.authService.setRedirectUrl(url); this.router.navigate([this.authService.getLoginUrl()]); return false; } canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean { const url: string = state.url; console.log('Url:' + url); if (this.authService.isUserLoggedIn()) { return true; } this.authService.setRedirectUrl(url); this.router.navigate([this.authService.getLoginUrl()]); return false; } }
AppRoutingModule
we have already configured AuthGuardService
with canLoad
property as given below.
{ path: 'admin', loadChildren: () => import('./admin/admin.module').then(mod => mod.AdminModule), canLoad: [ AuthGuardService ] }
AuthGuardService
with canActivate
property in AdminRoutingModule
that is routing module of feature module AdminModule
. Find the code.
admin-routing.module.ts
import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { AdminComponent } from './admin.component'; import { PersonListComponent } from './person-list/person.list.component'; import { AuthGuardService } from '../auth-guard.service'; const personRoutes: Routes = [ { path: '', component: AdminComponent, children: [ { path: 'person-list', component: PersonListComponent, canActivate: [ AuthGuardService ] } ] } ]; @NgModule({ imports: [ RouterModule.forChild(personRoutes) ], exports: [ RouterModule ] }) export class AdminRoutingModule {
Project Structure of Demo Application
Find the project structure of demo application.my-app | |--src | | | |--app | | | | | |--authentication | | | | | | | |--services | | | | | | | | | |--auth.service.ts | | | | |--user.ts | | | | | | | |--auth.module.ts | | | |--auth-routing.module.ts | | | |--login.component.css | | | |--login.component.html | | | |--login.component.ts | | | |--logout.component.ts | | | | | |--admin | | | | | | | |--admin.component.ts | | | |--admin-routing.module.ts | | | |--admin.module.ts | | | |--person.ts | | | | | | | |--person-list | | | | | | | | | |--person.list.component.html | | | | |--person.list.component.ts | | | | | | | | | | | | |--services | | | | | | | | | |--person.service.ts | | | | | |--address | | | | | | | |--address.component.ts | | | |--address-routing.module.ts | | | |--address.module.ts | | | | | |--auth-guard.service.ts | | | | | |--dashboard.layout.component.ts | | |--welcome.component.ts | | |--page-not-found.component.ts | | |--app.component.ts | | |--app-routing.module.ts | | |--app.module.ts | | | |--main.ts | |--index.html | |--styles.css | |--node_modules |--package.json
Complete Example
1. Code for Authentication Feature
auth.service.ts
import { Injectable } from '@angular/core'; import { Observable, of } from 'rxjs'; import { map } from 'rxjs/operators'; import { User } from './user'; const USERS = [ new User(1, 'mahesh', 'm123', 'ADMIN'), new User(2, 'krishna', 'k123', 'ADMIN') ]; let usersObservable = of(USERS); @Injectable() export class AuthService { private redirectUrl: string | undefined = '/'; private loginUrl: string = '/login'; private isloggedIn: boolean = false; private loggedInUser: User | null = null; getAllUsers(): Observable<User[]> { return usersObservable; } isUserAuthenticated(username: string, password: string): Observable<boolean> { return this.getAllUsers().pipe( map((users: User[]) => { let user = users.find(user => (user.username === username) && (user.password === password)); if (user) { this.isloggedIn = true; this.loggedInUser = user; } else { this.isloggedIn = false; } return this.isloggedIn; })); } isUserLoggedIn(): boolean { return this.isloggedIn; } getRedirectUrl(): string | undefined { return this.redirectUrl; } setRedirectUrl(url: string | undefined): void { this.redirectUrl = url; } getLoginUrl(): string { return this.loginUrl; } getLoggedInUser(): User | null { return this.loggedInUser; } logoutUser(): void { this.isloggedIn = false; } }
export class User { constructor(public userId:number, public username:string, public password:string, public role:string) { } }
import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { ReactiveFormsModule } from '@angular/forms'; import { LoginComponent } from './login.component'; import { AuthRoutingModule } from './auth-routing.module'; import { AuthService } from './services/auth.service'; @NgModule({ imports: [ CommonModule, ReactiveFormsModule, AuthRoutingModule ], declarations: [ LoginComponent ], providers: [ AuthService ] }) export class AuthModule { }
import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { LoginComponent } from './login.component'; const authRoutes: Routes = [ { path: 'login', component: LoginComponent } ]; @NgModule({ imports: [ RouterModule.forChild(authRoutes) ], exports: [ RouterModule ] }) export class AuthRoutingModule{ }
:host { position: absolute; background-color: #eaedf2; top: 10%; left: 5%; border: 3px solid black; }
<h3>Login Form</h3> <div *ngIf="invalidCredentialMsg" ngClass="error">{{invalidCredentialMsg}}</div> <div> <form [formGroup]="loginForm" (ngSubmit)="onFormSubmit()"> <p>User Name: <input formControlName="username"></p> <p>Password: <input type="password" formControlName="password"></p> <p><button type="submit">Submit</button></p> </form> </div>
import { Component } from '@angular/core'; import { FormControl, FormGroup } from '@angular/forms'; import { Router } from '@angular/router'; import { AuthService } from './services/auth.service'; @Component({ templateUrl: './login.component.html', styleUrls: ['./login.component.css'] }) export class LoginComponent { invalidCredentialMsg = ''; constructor(private authService: AuthService, private router: Router) { } loginForm = new FormGroup({ username: new FormControl(), password: new FormControl() }); onFormSubmit() { let uname = this.loginForm.get('username')?.value; let pwd = this.loginForm.get('password')?.value; this.authService.isUserAuthenticated(uname, pwd).subscribe( (authenticated: boolean) => { if (authenticated) { let url = this.authService.getRedirectUrl(); console.log('Redirect Url:' + url); this.router.navigate([url]); } else { this.invalidCredentialMsg = 'Invalid Credentials. Try again.'; } } ); } }
import { Component, OnInit } from '@angular/core'; import { Router } from '@angular/router'; import { AuthService } from './services/auth.service'; import { User } from './services/user'; @Component({ selector: 'logout', template: ` <div *ngIf="loggedInUser"> Logged In: {{loggedInUser.username}} | {{loggedInUser.role}} | <button input='input' (click)="logout()">Logout</button> </div> ` }) export class LogoutComponent { loggedInUser: User | null; constructor(private authService: AuthService, private router: Router) { this.loggedInUser = this.authService.getLoggedInUser(); } ngOnInit() { } logout() { this.authService.logoutUser(); this.loggedInUser = null; this.router.navigate(["/welcome"]); } }
2. Code for Admin Feature
admin.component.ts
import { Component } from '@angular/core'; @Component({ template: ` <h2>Welcome to Admin Home</h2> <a [routerLink]="['person-list']" routerLinkActive="active">View Person List</a> <router-outlet></router-outlet> ` }) export class AdminComponent { }
import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { AdminComponent } from './admin.component'; import { PersonListComponent } from './person-list/person.list.component'; import { AuthGuardService } from '../auth-guard.service'; const personRoutes: Routes = [ { path: '', component: AdminComponent, children: [ { path: 'person-list', component: PersonListComponent, canActivate: [ AuthGuardService ] } ] } ]; @NgModule({ imports: [ RouterModule.forChild(personRoutes) ], exports: [ RouterModule ] }) export class AdminRoutingModule { }
import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { AdminComponent } from './admin.component'; import { PersonListComponent } from './person-list/person.list.component'; import { PersonService } from './services/person.service'; import { AdminRoutingModule } from './admin-routing.module'; @NgModule({ imports: [ CommonModule, AdminRoutingModule ], declarations: [ AdminComponent, PersonListComponent ], providers: [ PersonService ] }) export class AdminModule { constructor() { console.log('AdminModule loaded.'); } }
export class Person { constructor(public personId:number, public name:string, public city:string) { } }
<h3>Person List</h3> <p *ngFor="let person of persons$ | async"> {{person.personId}}. {{person.name}} - {{person.city}} </p>
import { Component, OnInit } from '@angular/core'; import { Observable } from 'rxjs'; import { PersonService } from '../services/person.service'; import { Person } from '../person'; @Component({ templateUrl: './person.list.component.html' }) export class PersonListComponent implements OnInit { persons$: Observable<Person[]>; constructor(private personService: PersonService) { this.persons$ = this.personService.getPersons(); } ngOnInit() { } }
import { Injectable } from '@angular/core'; import { Observable, of } from 'rxjs'; import { Person } from '../person'; const PERSONS = [ new Person(1, 'Mahesh', 'Varanasi'), new Person(2, 'Ram', 'Ayodhya'), new Person(3, 'Kishna', 'Mathura') ]; let personList$ = of(PERSONS); @Injectable() export class PersonService { getPersons(): Observable<Person[]> { return personList$; } }
3. Code for Address Feature
address.component.ts
import { Component } from '@angular/core'; @Component({ template: ` <h3>ADDRESS</h3> <p><b> Article: Angular CanLoad Guard Example </b></p> <p><b> Category: Angular </b></p> <p><b> Website: CONCRETEPAGE.COM </b></p> <div> <a [routerLink]="['/location']">Find Location</a> </div> ` }) export class AddressComponent { }
import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { AddressComponent } from './address.component'; const addressRoutes: Routes = [ { path: '', component: AddressComponent } ]; @NgModule({ imports: [ RouterModule.forChild(addressRoutes) ], exports: [ RouterModule ] }) export class AddressRoutingModule { }
import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { AddressRoutingModule } from './address-routing.module'; import { AddressComponent } from './address.component'; @NgModule({ imports: [ CommonModule, AddressRoutingModule ], declarations: [ AddressComponent ] }) export class AddressModule { constructor() { console.log('AddressModule loaded.'); } }
4. Other components, services and modules
auth-guard.service.ts
import { Injectable } from '@angular/core'; import { CanLoad, CanActivate, Route, Router, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'; import { AuthService } from './authentication/services/auth.service'; @Injectable() export class AuthGuardService implements CanLoad, CanActivate { constructor(private authService: AuthService, private router: Router) { } canLoad(route: Route): boolean { const url = route.path; console.log('Url:' + url); if (this.authService.isUserLoggedIn()) { return true; } this.authService.setRedirectUrl(url); this.router.navigate([this.authService.getLoginUrl()]); return false; } canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean { const url: string = state.url; console.log('Url:' + url); if (this.authService.isUserLoggedIn()) { return true; } this.authService.setRedirectUrl(url); this.router.navigate([this.authService.getLoginUrl()]); return false; } }
import { Component } from '@angular/core'; @Component({ template: ` <nav [ngClass] = "'parent-menu'"> <ul> <li><a routerLink="/address" routerLinkActive="active">Address</a></li> <li><a routerLink="/admin" routerLinkActive="active">Admin</a></li> </ul> </nav> <logout></logout> <div [ngClass] = "'parent-container'"> <router-outlet></router-outlet> </div> ` }) export class DashboardLayoutComponent { }
import { Component } from '@angular/core'; @Component({ template: ` <h2>Welcome to Dashboard</h2> ` }) export class WelcomeComponent { }
import { Component } from '@angular/core'; import { Location } from '@angular/common'; @Component({ template: ` <h2>Page Not Found.</h2> <div> <button (click)="goBack()">Go Back</button> </div> ` }) export class PageNotFoundComponent { constructor(private location: Location) { } goBack(): void { this.location.back(); } }
.parent-menu ul { list-style-type: none; margin: 0; padding: 0; overflow: hidden; background-color: #333; } .parent-menu li { float: left; } .parent-menu li a { display: block; color: white; text-align: center; padding: 15px 15px; text-decoration: none; } .parent-menu li a:hover:not(.active) { background-color: #111; } .parent-menu .active{ background-color: #4CAF50; } .parent-container { padding-left: 10px; }
import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: ` <router-outlet></router-outlet> ` }) export class AppComponent { }
import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { PreloadAllModules } from '@angular/router'; import { WelcomeComponent } from './welcome.component'; import { DashboardLayoutComponent } from './dashboard.layout.component'; import { PageNotFoundComponent } from './page-not-found.component'; import { AuthGuardService } from './auth-guard.service'; const routes: Routes = [ { path: '', redirectTo: '/welcome', pathMatch: 'full' }, { path: '', component: DashboardLayoutComponent, children: [ { path: 'address', loadChildren: () => import('./address/address.module').then(mod => mod.AddressModule) }, { path: 'admin', loadChildren: () => import('./admin/admin.module').then(mod => mod.AdminModule), canLoad: [AuthGuardService] }, { path: 'welcome', component: WelcomeComponent }, { path: '**', component: PageNotFoundComponent } ] } ]; @NgModule({ imports: [ RouterModule.forRoot(routes, { preloadingStrategy: PreloadAllModules }) ], exports: [ RouterModule ], providers: [AuthGuardService] }) export class AppRoutingModule { }
import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppComponent } from './app.component'; import { WelcomeComponent } from './welcome.component'; import { LogoutComponent } from './authentication/logout.component'; import { DashboardLayoutComponent } from './dashboard.layout.component'; import { PageNotFoundComponent } from './page-not-found.component'; import { AppRoutingModule } from './app-routing.module'; import { AuthModule } from './authentication/auth.module'; @NgModule({ imports: [ BrowserModule, AuthModule, AppRoutingModule ], declarations: [ AppComponent, WelcomeComponent, LogoutComponent, DashboardLayoutComponent, PageNotFoundComponent ], providers: [ ], bootstrap: [ AppComponent ] }) export class AppModule { constructor() { console.log('AppModule loaded.'); } }
Run Application
To run the application, find the steps.1. Download source code using download link given below on this page.
2. Use downloaded src in your Angular CLI application. To install Angular CLI, find the link.
3. Run ng serve using command prompt.
4. Access the URL http://localhost:4200
We will get dashboard. Now access admin feature, we will be redirected to login page. Enter mahesh/m123 authentication and then we will be able to visit admin feature. Find the print screen of the output.

References
Common Routing TasksCanLoad Interface
Angular Route Guards: CanActivate and CanActivateChild Example