In an SPA, Angular routing is basically the functionality allowing users to travel between various parts of your app. At that point, the route guards, which will make navigation smarter and more secure.
Why Would We need Angular Guard Protection?
- Block Access: Let unauthorized users have no access to the routes you select.
- Role-Based Access Control: Grant or deny access according to user roles.
- Avoid Unsaved Data Loss: Prompt the user for unsaved changes when navigating away from the page.
- Preloading of Data Before Navigation: Load data needed before a component is routed in.
- Lazy Loading Optimization: Manage lazy loading of modules efficiently.
Types of Route Guards in Angular
There are five different types of route guards in Angular:
- canActivate: Checks whether the user can go to a certain route.
- canActivateChild: Determines whether users should be able to reach child routes.
- canDeactivate: Prevents users from leaving a route unless they meet some condition.
- resolve: It pre-loads data ahead of the route's activation.
- canLoad: Disallows loading of lazy-loaded modules if the condition is not met.
How to Use Route Guards in Angular
1. canActivate
- Block Access
This guard prevents unauthorized access to certain routes.
Implementation:
import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
@Injectable({ providedIn: 'root' })
export class AuthGuard implements CanActivate {
constructor(private router: Router) {}
canActivate(): boolean {
const isAuthenticated =!!localStorage.getItem('token');
if (!isAuthenticated) {
this.router.navigate(['/login']);
return false;
}
return true;
}
}
Usage:
{ path: 'dashboard', component: DashboardComponent, canActivate: [AuthGuard] }
2. canActivateChild
- Protect Child Routes
This guard restricts access to child routes just like canActivate
does for parent routes.
Implementation:
import { Injectable } from '@angular/core';
import { CanActivateChild, Router } from '@angular/router';
@Injectable({ providedIn: 'root' })
export class ChildAuthGuard implements CanActivateChild {
constructor(private router: Router) {}
canActivateChild(): boolean {
const hasPermission =!!localStorage.getItem('admin');
if (!hasPermission) {
this.router.navigate(['/']);
return false;
}
return true;
}
}
Usage:
{
path: 'admin',
component: AdminComponent,
canActivateChild: [ChildAuthGuard],
children: [
{ path: 'users', component: UsersComponent },
{ path: 'settings', component: SettingsComponent }]
}
3. canDeactivate
- Prevent Accidental Data Loss
This guard prevents the user from navigating away from a certain component if there are unsaved changes.
Solution:
import { Injectable } from '@angular/core';
import { CanDeactivate } from '@angular/router';
import { Observable } from 'rxjs';
export interface CanComponentDeactivate {
canDeactivate: () => Observable<boolean> | Promise<boolean> | boolean;
}
@Injectable({ providedIn: 'root' })
export class CanLeaveGuard implements CanDeactivate<CanComponentDeactivate> {
canDeactivate(component: CanComponentDeactivate): boolean {
return component.canDeactivate? component.canDeactivate() : true;
}
}
Component Implementation:
import { Component } from '@angular/core';
import { CanComponentDeactivate } from './guards/can-leave.guard';
@Component({
selector: 'app-profile',
templateUrl: './profile.component.html'
})
export class ProfileComponent implements CanComponentDeactivate {
unsavedChanges = true;
canDeactivate(): boolean {
return this.unsavedChanges? confirm('You have unsaved changes. Leave anyway?') : true;
}
}
Usage:
{ path: 'profile', component: ProfileComponent, canDeactivate: [CanLeaveGuard] }
4. resolve
- Fetch Data Before Route Activation
This ensures that data are fetched before the route is activated.
Implementation:
import { Injectable } from '@angular/core';
import { Resolve } from '@angular/router';
import { Observable, of } from 'rxjs';
@Injectable({ providedIn: 'root' })
export class UserResolver implements Resolve<any> {
resolve(): Observable<any> {
return of({ name: 'John Doe', age: 30 }); // Example API call
}
}
Usage:
{ path: 'user', component: UserComponent, resolve: { userData: UserResolver } }
How to access resolved data in Component:
import { ActivatedRoute } from '@angular/router';
constructor(private route: ActivatedRoute) {}
ngOnInit() {
const user = this.route.snapshot.data['userData'];
console.log(user);
}
5. canLoad
- Blocking Lazy Module Loading
This guard prevents lazy-loaded modules to be loaded in case conditions aren't met.
Implementation:
import { Injectable } from '@angular/core';
import { CanLoad, Route, UrlSegment, Router } from '@angular/router';
@Injectable({ providedIn: 'root' })
export class AdminLoadGuard implements CanLoad {
constructor(private router: Router) {}
canLoad(route: Route, segments: UrlSegment[]): boolean {
const isAdmin =!!localStorage.getItem('admin');
if (!isAdmin) {
this.router.navigate(['/']);
return false;
}
return true;
}
}
Usage:
{ path: 'admin', loadChildren: () => import('./admin/admin.module').then(m => m.AdminModule), canLoad: [AdminLoadGuard] }
Conclusion
Route guards in Angular play a great role in route protection, navigation control, and optimization of performance. You will efficiently manage your users' access and data flow within your applications by implementing the different guards of canActivate
, canActivateChild
, canDeactivate
, resolve
, and canLoad
.
Top comments (0)