a blog for those who code

Saturday, 16 March 2019

Understanding Route Guards in Angular

Routing is one of the important aspects of any Web Application be it a single page app or a multi-page application. Angular uses Angular Router (@angular/router package) which enables the navigation from one view to other as and when users perform any tasks. Angular Router provides a routing library which helps in maintaining multiple router outlets, access to route parameters and route guards which helps to protect the route from unauthorized access.



Understanding Routing in Angular


Route Guards are interfaces which tells the router that should the navigation be allowed to a requested route or not. So a logic is ran whenever a route is requested and based on that logic, it allows or denies the access to the route. For example, to check if the user is logged in or for showing admin pages.

There are mainly 5 types of guards :

1. CanActivate - checks if a user can visit the route
2. CanActivateChild - checks if a user can visit the routes children
3. CanDeactivate - checks to see if a user can exit a route
4. CanLoad - checks to see if a user can route to a module that lazy loads
5. Resolve - it performs data retrieval before route activation

For a route you can implement zero to any number of Guards. If any guard returns false, other guards that have not been completed will be canceled and the navigation is cancelled.

1. CanActivate - This guard can return true if the user has access or false if they do not have, they can also return an Observable or Promise which resolves to a boolean. A simple CanActivate Guard looks like below which always returns true that means allowing users to navigate to that route.

import { CanActivate, 
         ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs/Observable';

export class MyAuthGuard implements CanActivate {
  canActivate(route: ActivatedRouteSnapshot,
              state: RouterStateSnapshot): 
                       Observable<boolean> | Promise<boolean> | boolean {
    return true;
  }
}

And thus we can use our Guard as shown below :

const routes: Routes = [
  {
    path: '',
    canActivate: [MyAuthGuard],
    component: HomeComponent
  }, {
    path: '**',
    component: NotFoundComponent
  }
];

The Guard does not really does anything, but we can write a logic inside our canActivate method to see if a User is Logged in or not and based on that we can allow the users to navigate to the route.

2. CanActivateChild - Just like CanActivate we have CanActivateChild, logic is similar for both.

import { CanActivateChild, 
         ActivatedRouteSnapshot,
        RouterStateSnapshot } from '@angular/router';
import { Observable } from 'rxjs/Observable';

export class MyAuthGuard implements CanActivateChild {
  canActivate(route: ActivatedRouteSnapshot,
              state: RouterStateSnapshot): 
                       Observable<boolean> | Promise<boolean> | boolean {
    return true;
  }
}

And thus if any route has any children, it checks the canActivateChild to see if the user has permission to visit that route.

Custom Bindings using Input and Output Properties in Angular 7


3. CanDeactivate - This is very useful route if you have any form property in your route where you get data from user. This type of route is used to warn users if they are navigating away from the page where the page have some unsaved data.

So at first we will create a component MyComponent in that we have a canDeactivate function as shown below where we will write the logic if the user can navigate or not.
canDecativate() {
  // Logic to return true or false
}

Now we will create a Deactivate Guard as shown below where it accepts the component, activated route and router state, now based on the Component's canDeactivate boolean value our CanDeactivateGuard will decide if the user can navigate away or not.

export class CanDeactivateGuard implements CanDeactivate<MyComponent> {
  canDeactivate(component: MyComponent,
                route: ActivatedRouteSnapshot,
                state: RouterStateSnapshot): 
                    Observable<boolean> | Promise<boolean> | boolean {
    return component.canDeactivate();
  }
}

4. CanLoad - If you are using canActivate Guard or canActivateChild Guard you are not allowing the user to view the route or say component, but the component is getting loaded by the angular. If you do not want to load the component itself, you can use CanLoad Guard. A simple CanGuard auth looks like below, now we can use both CanLoad and CanActivate on the route if the  user is not an admin if we are restricting Admin Route.

import { CanLoad, Route } from '@angular/router';
import { Observable } from 'rxjs/Observable';

export class MyAuthGuard implements CanLoad {
  canLoad(route: Route): boolean {
    return true;
  }
}

5. Resolve - This will allow us to run some code before a route is rendered, the difference it will have with canActivate is that resolver will not decide if the route should be shown or not, it will just run some code and navigate to the route at the end. So in a simple term resolver is an intermediate code, which is execute when a route is clicked and before a component is loaded. The resolve method will give you an Observable, Promise or actual values.

import { Resolve, 
         ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router'

interface MyInterface {
  key: number;
  value: string;
}

export class ServerResolver implements Resolve<MyInterface> {
  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot)
  : Observable<Server> | Prmoise<Server> | Server {
    return new Server {key: 1, value: '1'};
  }
}

I hope now you have the basic understanding of the Route Gurads and how they work.

No comments:

Post a comment