Routing guards in Angular 2

H
ere we will be discussing how routing guards in Angular works.

Suppose we have a couple of routes in your Angular 2 application and some of the routes expose some highly confidential data. Do you want to expose such type of routes publically?

Consider another scenario, where you have admin routes that can perform all CURD operations in the application. I am sure you don't want anyone to mess up with your components. The solution is to protect your routes using guards so that only authorized individual can only access your routes.

Above are the daily based scenarios where you need to configure guards. Apart from this, there can be other scenarios as well where you need to configure guards on your routes:

  • When we need to fetch some data before displaying the target component.
  • When we need to save pending changes before leaving a component
  • When we sometimes need to ask the user if it's OK to discard pending changes rather than save them.

Now we have a basic understanding why we need to configure route guards in our application. Let's get started understanding more about guards and how to configure them in our application. 

Let's look at different type of guards that we have in Angular and see how to configure them in our Angular app.

Guard types

There are four different guard types we can use to protect our routes:

  1. CanActivate - Decides if a route can be activated
  2. CanActivateChild - Decides if children routes of a route can be activated
  3. CanDeactivate - Decides if a route can be deactivated
  4. CanLoad - Decides if a module can be loaded lazily
  5. Resolve- to perform route data retrieval before route activation.

We can configure one or more than one guard for our routes.

Guards configured on routes always returns either true or false.

  1. If guards returns true, then a user is navigated to the requested route.
  2. If guard returns false, the user is not navigated

A routing guard can return an Observable<boolean> or a Promise<boolean> and the router will wait for the observable to resolve to true or false.

CanActivate

A very simple guard looks like as shown below:

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

@Injectable()
export class MyFirstGuard implements CanActivate {

     canActivate() {
         console.log('My route is protected with guards');
         return true;
     }
}

The above guard demonstrates a simple use of CanActivate guard. Here in the above guard, we are simply returning 'true' so that user is navigated to the page. In the actual application, there is much more we can do with guards.

How to use the guard that we have created above?

It's very easy by just adding it to our routing.ts file a shown below:

const routes: Routes = [ 
       { path: 'home', component: HomeComponent }, 
       { path: 'admin', component: AdminComponent, canActivate: [MyFirstGuard] } 
];


Now, wherever user tries to access /admin user need to pass validation that we have in MyFirstGuard guard. (In our case we are directly returning true, so it is directly accessible).

Also, we need to register our guard as a provider in `app.module.ts` file.

There is a scenario where developer wants to do asynchronous validations (service request) returning Boolean in guards. Even that is also achievable in guards.

For example: If we need to check the access of a user to route by calling service we can do that as well.

CanActivateChild 

The CanActivateChild guard is similar to the CanActivate guard. The key difference is that it runs before any child route is activated.

For example: In above case, we have protected admin route with help of CanActivate guard, but what if there are child routes in admin routes. like: /admin/createUser we definitely want to protect that too as well. We can do that with help of CanActivateChild route guard.

We can extend our MyFirstGuard itself to protect our child routes as well. Please follow the example shown below:

import { Injectable } from '@angular/core';
import { CanActivate,CanActivateChild } from '@angular/router';

@Injectable()
export class MyFirstGuard implements CanActivate {

       canActivate(): boolean {
            console.log('My route is protected with guards');
            return true;
       }

        canActivateChild(): boolean {
              console.log('Protecting child routes as well');
              return true;
         }
}

Now we need to add children routes to our admin route to see CanActivateChild in action:

const routes: Routes = [ 
     { path: 'home', component: HomeComponent }, 
     { path: 'admin', component: AdminComponent, canActivate: [MyFirstGuard],
           children: [
              { path: 'update', component: UpdateDetailsComponent, canActivateChild: [AuthGuard] } 
           ] 
      } 
];

​​​CanDeactivate

Its functionality is just reverse of CanActivate as the name suggest. It is executed when a user is about to leave the route. Consider an example as shown below to understand its use case in a better way:

Suppose we have a big form and user is filling the form and accidentally user cancel or click back button (or any action that will navigate him away from the form). Then the whole data that the user has filled will be lost. But if we have CanDeactivate guard enabled it will help a user to confirm before navigation hence saving his time and efforts to fill the form again.

Now we have an understanding of CanDeactivate guard lets see the code for it.

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

@Injectable()
export class MyDeactivateGuard implements CanDeactivate<AdminComponent> {                                                                            canDeactivate(component: AdminComponent)  {
                 return component.confirmRedirect();
          }
}

As we can see the code is quite similar to CanActivate guard but there are some changes like CanDeactive requires the component that is being deactivated as a parameter.

CanLoad

As we have seen earlier we use a canActivate guard to restrict access for unauthorized users but CanLoad guard can be used to prevent application to load the entire module if a user doesn't have access to the route.

Let us see this in action with help of an example:

const routes: Routes = [
      { path: 'admin', loadChildren: 'app/admin.module#AdminModule', canLoad: [MyFirstGuard] }
];

Here in above example if AuthGuard returns true then only AdminModule will be loaded in the application.

Resolve

Suppose there is a route where we are pulling data from the restful endpoint (service) and we only want to route user only if the service status is a success. Then resolve route can help us. So basically what resolve route does is, it preloads the data before navigating user to the route.

What I would say is when you want a route to delay till the time component data is ready we should use resolve route.

resolve(route: ActivatedRouteSnapshot): Observable<any> {

             let id = route.params['id'];
             return this.getUser(id) .map(data => {
                       if(data) {
                             return user;
                        } else {
                              this.router.navigate(['/details']); 
                               return false;
                         }
               }) 
}

In above example, we are calling service getUser() and if the response is a success we are navigating but if the response is a failure we are redirecting user to the details page.

I hope this post is helpful for you to understand route guards in depth. Stay tuned for upcoming posts.

Author Info

Tavish Aggarwal

Website: http://tavishaggarwal.com

Tavish Aggarwal is a front-end Developer working in a Hyderabad. He is very passionate about technology and loves to work in a team.

Category