What are Guards in Angular and How to Use Them for Route Protection?

In Angular, guards are used to control access to routes and prevent unauthorized access to certain parts of an application. Guards can be used to check if a user is authenticated, if they have permission to access a certain page, or if certain conditions are met before allowing access to a route.

There are several types of guards in Angular:

  1. `CanActivate`: This guard is used to check if a user is allowed to activate a route. It is typically used to check if a user is authenticated or has the required permissions to access a route.
  2. `CanActivateChild`: This guard is used to check if a user is allowed to activate child routes. It is similar to `CanActivate`, but it is applied to child routes instead of the parent route.
  3. `CanDeactivate`: This guard is used to check if a user is allowed to deactivate a route. It is typically used to check if a user has unsaved changes that they may lose if they navigate away from a page.
  4. `Resolve`: This guard is used to resolve data before a route is activated. It is typically used to fetch data from an API or a server before displaying a page.

CanActivate Guard

Here's an example of how to use a CanActivate guard to check if a user is authenticated before allowing them to access a route:

typescript
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.isAuthenticated()) {
      return true;
    } else {
      this.router.navigate(['/login']);
      return false;
    }
  }
}

In this example, the `AuthGuard` checks if a user is authenticated by calling the `isAuthenticated()` method on an `AuthService` object. If the user is authenticated, the guard returns true, allowing access to the route. If the user is not authenticated, the guard redirects them to the login page and returns `false`, preventing access to the route.

To use this guard in a route, you can add it to the `canActivate` property of the route definition:

typescript
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';

const routes: Routes = [
  { path: '', component: HomeComponent, canActivate: [AuthGuard] },
  { path: 'login', component: LoginComponent }
];

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

In this example, the `AuthGuard` is added to the `canActivate` property of the home route, ensuring that the user is authenticated before allowing access to the home page.

CanDeactiveGuard

`CanDeactivate` is a route guard in Angular that allows you to prevent users from navigating away from a page if certain conditions are not met. This guard is useful for preventing users from accidentally losing unsaved changes or data.

The `CanDeactivate` guard requires you to implement a method called `canDeactivate` in your component. This method should return a boolean or a Promise or an Observable that resolves to a boolean value. If the value is `true`, the user is allowed to navigate away from the page. If the value is `false`, the user is prevented from navigating away from the page.

Here's an example of how to use the `CanDeactivate` guard to prevent users from navigating away from a page if unsaved changes exist:

typescript
import { Injectable } from '@angular/core';
import { CanDeactivate } from '@angular/router';
import { Observable } from 'rxjs';
import { EditComponent } from './edit.component';

@Injectable({
  providedIn: 'root'
})
export class CanDeactivateGuard implements CanDeactivate<EditComponent> {

  canDeactivate(component: EditComponent): Observable<boolean> | Promise<boolean> | boolean {
    if (component.hasUnsavedChanges()) {
      return confirm('Are you sure you want to discard your changes?');
    } else {
      return true;
    }
  }
}

In this example, the `CanDeactivateGuard` implements the `CanDeactivate` interface and defines a `canDeactivate` method that takes an instance of the `EditComponent` as an argument. The `EditComponent` has a method called `hasUnsavedChanges()` that returns `true` if there are unsaved changes on the page.

The `canDeactivate` method checks if there are unsaved changes on the page. If there are, it displays a confirmation dialog asking the user if they want to discard their changes. If the user confirms, the method returns `true`, allowing the user to navigate away from the page. If the user cancels the dialog, the method returns `false`, preventing the user from navigating away from the page.

To use this guard in a route, you can add it to the `canDeactivate` property of the route definition:

typescript
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { EditComponent } from './edit/edit.component';
import { CanDeactivateGuard } from './can-deactivate.guard';

const routes: Routes = [
  { path: 'edit', component: EditComponent, canDeactivate: [CanDeactivateGuard] }
];

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

In this example, the `CanDeactivateGuard` is added to the `canDeactivate` property of the `edit` route. This ensures that the user is prompted to confirm if there are unsaved changes before navigating away from the `edit` page.

Summary

Overall, guards provide a powerful way to control access to routes and prevent unauthorized access to parts of an application. They allow you to add an extra layer of security to your application and ensure that users can only access the parts of the application that they are authorized to access.

Preview the code on GitHub