Support us .Net Basics C# SQL ASP.NET Aarvi MVC Slides C# Programs Subscribe Download

Angular route guards

Suggested Videos
Part 36 - Angular property setter vs ngonchanges | Text | Slides
Part 37 - Angular component communication | Text | Slides
Part 38 - Call child component methods and properties | Text | Slides

In this video we will discuss CanDeactivate route guard in Angular. We will also discuss how to access angular template reference variable in component class.


First let's understand, why route guards are required. Consider the following "Create Employee" data entry form. This is a pretty big form. Let's say you have filled 90% of the form fields and you accidentally clicked on the "List" navigation link. The application immediately redirects you to the "list" route and all your data on the "Create Employee" form is lost. Wouldn't it have been nice if there was an alert asking the user if he really wants to discard his changes and navigate away from the Create Employee form


angular candeactivate example

A routing guard called CanDeactivate can help us achieve this very easily. The following table has the common routing guards and their purpose.

Route Guard Use
CanDeactivate Guard navigation away from the current route
CanActivate Guard navigation to a route
CanActivateChild Guard navigation to a child route
CanLoad Guard navigation to a feature module loaded asynchronously
Resolve Perform route data retrieval before route activation

We will discuss each of these routing guards with an example in our upcoming videos. In this video we will discuss CanDeactivate guard.

There are 3 steps to use a routing guard in Angular.
  • Build the route guard
  • Register the guard with angular dependency injection system
  • Tie the guard to a route 
Building the route guard : A route guard can be implemented as a function or a service. In this video let's create a service. In our upcoming videos we will discuss creating a function.

Create a new file, in the employees folder. Name it create-employee-can-deactivate-gaurd.service.ts. Copy and paste the following code.

import { Injectable } from '@angular/core';
import { CanDeactivate } from '@angular/router';
import { CreateEmployeeComponent } from './create-employee.component';

@Injectable()
export class CreateEmployeeCanDeactivateGuardService
    implements CanDeactivate<CreateEmployeeComponent> {

    constructor() { }

    canDeactivate(component: CreateEmployeeComponent): boolean {
        if (component.createEmployeeForm.dirty) {
            return confirm('Are you sure you want to discard your changes?');
        }

        return true;
    }
}

Code Explanation : 
  • Since we are implementing the routing guard as a service, decorate the guard class with @Injectable() decorator.
  • Since we want to implement CanDeactivate routing guard, make the guard class implement CanDeactivate interface.
  • CanDeactivate interface supports generics. In our case, since we are creating a guard for CreateEmployeeComponent, we have specified CreateEmployeeComponent as the argument for the generic type of CanDeactivate interface.
  • CanDeactivate interface has one method called canDeactivate(). Our routing guard class needs to provide implementation for this interface method.
  • canDeactivate() method returns true or false. True to allow navigation away from the route. False to prevent navigation.
  • The first parameter that is passed to the canDeactivate() method is the CreateEmployeeComponent. We are using this parameter to check if the component is dirty. If it is dirty, we are triggering JavaScript confirm dialog to the user.
  • If the component is not dirty we simply return true, to allow navigation away from the "create" route.
How to check if the form is dirty : Include the following line of code in CreateEmployeeComponent class
@ViewChild('employeeForm') public createEmployeeForm: NgForm;

@ViewChild() decorator provides access to the NgForm directive in the component class. employeeForm which is passed as the selector to the @ViewChild() decorator is the form template reference variable. 

The public property "createEmployeeForm" is used to check if the form is dirty.

Register the guard with angular dependency injection system : Since the routing guard is implemented as a service, we need to register it in a module. At the moment we have only one module in our application and that is the root module AppModule. Import and register CreateEmployeeCanDeactivateGuardService in app.module.ts file using the providers property.

@NgModule({
  declarations: […
  ],
  imports: […
  ],
  providers: [CreateEmployeeCanDeactivateGuardService],
  bootstrap: [AppComponent]
})
export class AppModule { }

Tie the guard to a route : Using the route guard, we want to prevent navigating away from the "create" route, so tie the route guard with the "create" route in app.module.ts file as shown below.

const appRoutes: Routes = [
  {
    path: 'list', component: ListEmployeesComponent
  },
  {
    path: 'create',
    component: CreateEmployeeComponent,
    canDeactivate: [CreateEmployeeCanDeactivateGuardService]
  },
  {
    path: '', redirectTo: '/list', pathMatch: 'full'
  }
];

At this point, if you try to navigate away from the "create" route when the form is dirty you get the alert as expected. The browser back and forward buttons also prevent the navigation away from the "create" route.

CanDeactivate limitations : CanDeactivate guard does not prevent route deactivation
  • If you type a different url in the address bar directly OR
  • If you close the tab or the browser window OR
  • If you navigate to an external URL
angular crud tutorial

3 comments:

  1. is auth guard and route guard are same?

    ReplyDelete
  2. HI ALL,
    please use this line of code if u are working with angular8.
    @ViewChild('employeeForm',{static:true}) public createEmployeeForm: NgForm;

    ReplyDelete
  3. Dear venkat
    Could you please make some videos about webpack in angular.

    ReplyDelete

It would be great if you can help share these free resources