One of the most useful features of an Angular application is the ability to manage route access with Angular Guards. They aid in application security by deciding whether or not a user can access a specific route. An in-depth explanation of angular guards, including their types, applications, and real-world examples, will be given in this article.
Angular Guard Types
Angular offers five different kinds of guards.
- CanActivate: Ascertains the possibility of activating a route.
- CanActivateChild: Ascertains whether it is possible to activate a child route.
- CanDeactivate: Ascertains if deactivating a route is possible.
- Before a route is activated, resolve pre-fetches of data.
- Checks whether a module can be loaded slowly using the CanLoad function.
1. Capabilities to Activate
To determine whether a route can be activated, utilize the CanActivate guard. It is frequently employed for permission and authentication needs.
import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';
import { AuthService } from './auth.service';
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor(
private authService: AuthService,
private router: Router
) {}
canActivate(): boolean {
if (this.authService.isLoggedIn()) {
return true;
} else {
this.router.navigate(['login']);
return false;
}
}
}
2. CanActivateChild
The CanActivateChild guard works similarly to CanActivate but is applied to child routes.
import { Injectable } from '@angular/core';
import { CanActivateChild, Router } from '@angular/router';
import { AuthService } from './auth.service';
@Injectable({
providedIn: 'root'
})
export class ChildAuthGuard implements CanActivateChild {
constructor(private authService: AuthService, private router: Router) {}
canActivateChild(): boolean {
if (this.authService.isLoggedIn()) {
return true;
} else {
this.router.navigate(['login']);
return false;
}
}
}
3. CanDeactivate
The CanDeactivate guard is used to decide if a route can be exited. It is useful for prompting the user to save changes before navigating away from a form.
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 CanDeactivateGuard implements CanDeactivate<CanComponentDeactivate> {
canDeactivate(component: CanComponentDeactivate): Observable<boolean> | Promise<boolean> | boolean {
return component.canDeactivate ? component.canDeactivate() : true;
}
}
4. Resolve
The Resolve guard pre-fetches data before a route is activated, ensuring that the required data is available when the route is activated.
import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs';
import { DataService } from './data.service';
@Injectable({
providedIn: 'root'
})
export class DataResolver implements Resolve<any> {
constructor(private dataService: DataService) {}
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<any> {
return this.dataService.getData();
}
}
5. CanLoad
The CanLoad guard is used to determine if a module can be loaded lazily. It prevents the loading of modules if certain conditions are not met.
import { Injectable } from '@angular/core';
import { CanLoad, Route, UrlSegment, Router } from '@angular/router';
import { AuthService } from './auth.service';
@Injectable({
providedIn: 'root'
})
export class CanLoadGuard implements CanLoad {
constructor(
private authService: AuthService,
private router: Router
) {}
canLoad(route: Route, segments: UrlSegment[]): boolean {
if (this.authService.isLoggedIn()) {
return true;
} else {
this.router.navigate(['login']);
return false;
}
}
}
Implementing Guards in Routes
To use guards in your routes, you need to add them to the route configuration.
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { LoginComponent } from './login/login.component';
import { AuthGuard } from './auth.guard';
import { ChildAuthGuard } from './child-auth.guard';
import { CanDeactivateGuard } from './can-deactivate.guard';
import { DataResolver } from './data.resolver';
import { CanLoadGuard } from './can-load.guard';
import { AdminComponent } from './admin/admin.component'; // Assuming you have this component
import { SettingsComponent } from './settings/settings.component'; // Assuming you have this component
import { FormComponent } from './form/form.component'; // Assuming you have this component
const routes: Routes = [
{
path: 'home',
component: HomeComponent,
canActivate: [AuthGuard],
resolve: { data: DataResolver }
},
{ path: 'login', component: LoginComponent },
{
path: 'admin',
component: AdminComponent,
canActivateChild: [ChildAuthGuard],
children: [
{ path: 'settings', component: SettingsComponent }
]
},
{
path: 'form',
component: FormComponent,
canDeactivate: [CanDeactivateGuard]
},
{
path: 'lazy',
loadChildren: () => import('./lazy/lazy.module').then(m => m.LazyModule),
canLoad: [CanLoadGuard]
}
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
Conclusion
The management of access control in your apps requires the use of Angular Guards. They offer a method for effectively managing user rights and putting security checks into place. You may make sure that your application operates correctly in a variety of scenarios, including data pre-fetching, authorization, authentication, and avoiding unsaved changes, by utilizing the different kinds of guards. Implementing guards effectively can enhance the security and usability of your Angular application, making it robust and user-friendly.
Happy Coding!