Guard Functions in Angular

Introduction

Guard functions in Angular play a crucial role in controlling the navigation flow within an application. Whether you're securing routes, handling authentication, or implementing role-based access, guard functions provide a powerful mechanism to enforce rules before allowing users to navigate to specific components. In this article, we'll explore the concept of guard functions in Angular, understand their types, and delve into practical implementations with code snippets.

What is Guard Functions?

Guard functions in Angular are used to protect routes and control the navigation process. They can be employed to enforce access control rules, perform authentication checks, and validate user permissions before allowing them to navigate to a particular route. Angular provides several types of guard functions, each serving a distinct purpose.

Types of Guard Functions


1. CanActivate

The CanActivate guard function is used to determine if a route can be activated. It returns a boolean or an observable/promise that resolves to a boolean. If true, the route activation proceeds; otherwise, the navigation is halted.

consider an example where we have an AuthGuard implementing CanActivate.

// auth.guard.ts

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, 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(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): boolean {
      
    if (this.authService.isAuthenticated()) {
      return true;
    }

    // Redirect to the login page if not authenticated
    this.router.navigate(['/login']);
    return false;
  }
}

In this example, the AuthGuard checks if the user is authenticated using the AuthService. If authenticated, the route activation proceeds; otherwise, the user is redirected to the login page.

2. CanActivateChild

The CanActivateChild guard function is similar to CanActivate, but it is specifically designed to guard child routes of a component.

// auth.guard.ts
// ...

export class AuthGuard implements CanActivateChild {
  canActivateChild(

    childRoute: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): boolean {
          return this.canActivate(childRoute, state);
  }
}

In this example, the CanActivateChild simply delegates to the CanActivate implementation.

3. CanDeactivate

The CanDeactivate guard function is used to determine if a route can be deactivated. It is often used for confirmation dialogs or to prevent users from accidentally leaving a page with unsaved changes.

// unsaved-changes.guard.ts

import { Injectable } from '@angular/core';
import { CanDeactivate } from '@angular/router';

export interface CanComponentDeactivate {

  canDeactivate: () => boolean;
}

@Injectable({
  providedIn: 'root',

})

export class UnsavedChangesGuard implements CanDeactivate<CanComponentDeactivate> {
  canDeactivate(

    component: CanComponentDeactivate): boolean {
          return component.canDeactivate ? component.canDeactivate() : true;
  }
}

In this example, the UnsavedChangesGuard is designed to work with components that implement the CanComponentDeactivate interface.

Gaurd Function in Routing Configuration

we can use these guard functions in the routing configuration as per the below code snippet.

// app-routing.module.ts

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { LoginComponent } from './login/login.component';
import { AuthGuard } from './auth.guard';
import { UnsavedChangesGuard } from './unsaved-changes.guard';

const routes: Routes = [

  { path: '', component: HomeComponent, canActivate: [AuthGuard] },
  { path: 'login', component: LoginComponent },
  {

    path: 'profile',

    loadChildren: () => import('./profile/profile.module').then(m => m.ProfileModule),
    canActivate: [AuthGuard],
    canActivateChild: [AuthGuard],
    canDeactivate: [UnsavedChangesGuard],

  },
];

@NgModule({

  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]

})

export class AppRoutingModule { }

In this example, the AuthGuard is applied to the root route and the CanActivateChild and CanDeactivate guards are applied to the 'profile' route.

Conclusion

Guard functions in Angular provide a powerful mechanism for controlling navigation and enforcing access rules within your application. By understanding the types of guard functions and their use cases, you can implement robust security measures and improve the overall user experience. Whether it's ensuring authentication, controlling route activation, or handling unsaved changes, guard functions are an essential tool in your Angular development toolbox.

As you continue to build complex applications, mastering guard functions will contribute to the security and reliability of your Angular projects.