DEV Community

Gaëtan Redin
Gaëtan Redin

Posted on • Originally published at Medium on

Routes Access Controlled by Angular Guards

Angular for every one: Part 14

Use cases and how to

Often, we see examples of routing guards around the authentication but I find that too much reductive. Actually, it’s simply a control which allows or not to access to parts of the application.

There are several kinds of guards:

  • CanActivate
  • CanActivateChild
  • CanDeactivate
  • Resolve
  • CanLoad

Use cases

So if it’s not to check if the user is authenticated then what’s for?

Roles

Well, beyond the authentication you can have to handle roles accesses. If your application is intended for operators and supervisors, probably supervisors can do more actions and can have access to more informations.

Fetching data

Maybe the target component requires data and it does not make sense to load it without this data. You should know that I have already written an article about this.

Using Angular Resolver to Pre Load Data

Save before leaving

You could have a workflow in your application which is a row of forms. You could need to save pending changes.

Discard or leave

Just a common case, the user has made some changes and click on a button without saving it. It could be nice in this case to check he is ok to discard his changes or not.

Defeat cunning devil

Some users can understand the routing system in place and that could be a problem. Imagine your workflow is based on routes and someone try to reach directly the second step which needs data from the first one… it could be a catastrophic user experience.

Guards in action

For all it’s the same logic, you have to choose the interface to implement. Here we will implement CanActivate guard.

interface CanActivate {
  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree
}
Enter fullscreen mode Exit fullscreen mode

This is how to:

@Injectable({
    providedIn: 'root',
})
_export class_ MyGuard _implements CanActivate_ {
    _constructor_(/* everything you need */) {}

    _public_ canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
        // Do your checks
    }
}
Enter fullscreen mode Exit fullscreen mode

What your guard should return? It depend of what you want to do but here’s some tips:

  • If it returns an Observable, you have to know that the navigation will be blocked until it’s not complete.
  • If it returns false, the navigation process stops and the user stays put.
  • If you use router.navigate or router.navigateByUrl, you have to return true to continue the navigation process.
  • You can return a UrlTree object to stop the current navigation and initialize a new one

Example of how to return a UrlTree:

_constructor_(private _router: Router) {}

_public_ canActivate(): boolean | UrlTree {
  if (!myCondition) {
    return this._router.parseUrl('/my-existing-route/in-my-app');
  }
  return true;
}
Enter fullscreen mode Exit fullscreen mode

Conclusion

As you can see, Angular’s routing features provide a lot of possibilities and let you how to protect and manage the access of your routes. One more time, it responds to the principle of separation of concern. Of course you can do all of this directly inside your components. But it will less readable and understandable… Just don’t forget that if your guard returns false or nothing the navigation will be stopped. The usual, adapt the implementation of your solution from your need, not the other way around.

Thanks for reading.

Learn More

Discussion (0)