Angular for everyone: Part 14

How to Use Angular Route Guards

Access Controlling with Angular Route Guards

Redin Gaetan
3 min readSep 11, 2021

Often, we see examples of routing guards around the authentication, but I find that too reductive. Actually, it’s simple to control, which allows or does not access 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. For example, if your application is intended for operators and supervisors, supervisors can probably do more actions and access more information.

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.

Save before leaving

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

Discard or leave

Just a common cause, 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. For example, imagine your workflow is based on routes, and someone tries 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
}

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
}
}

What should your guard return? It depends on what you want to do but here are 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;
}

Conclusion

As you can see, Angular’s routing features provide a lot of possibilities and let you protect and manage your routes' access. 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 be 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.

--

--