canMatch Router Guard

After introducing guards and the most common guard functions (canActivate, canActivateChild, and canDeactivate), we will cover one slightly different guard that can run when trying to access a route.

canMatch was introduced in Angular 15.1. When canMatch returns false, Angular will continue looking at other routes that would match that path instead of preventing any navigation.

Let’s consider the following example:

With the above code, both routes are configured for the /user path, but if the user is an admin user, they’ll land on an AdminDetails component, and if they’re a regular user, they’ll land on a UserDetails component.

This approach can be helpful when working with multiple user roles that display different components.

Route guards – canActivate, canActivateChild, canDeactivate

Yesterday, we introduced how route guards can control whether or not a user can navigate to a new URL in our application.

The main guard to achieve that behavior is canActivate. This guard will run every time the user tries to access a path and only allow the user to proceed if the guard function returns true.

Here’s an example that’s going to check if the user is logged in before proceeding:

If we want to redirect the user to a login component when they’re not logged in, we can do so by using the Router service and returning a UrlTree object as follows:

Note how the inject function is used in all these guards to access any service we need.

canActivate works well when navigating to components. If we want to prevent the lazy-loading of a child route or prevent access to any path of the child route, then canActivateChild is what we need instead of canActivate.

Finally, if you want to prevent the user from navigating away from the current path/component, you can implement the canDeactivate guard. A typical example of such a use case is when working with complex forms where we want to make sure the user has saved their progress before navigating away from the current screen/component:

Another exciting feature is that we can access the current component itself instead of a service, which is especially useful for canDeactivate:

If you like those new framework features, I covered some more utility router functions released with Angular 14+ in this post.

How to use Angular route guards?

The Angular router has 5 different route guards that can be used to control user navigation in the browser.

Such guards can be used in scenarios such as:

  • Preventing users from navigating to parts of an application without authorization
  • Preventing users from leaving a form before it is saved or completed
  • Making sure the user is logged in before proceeding to the next page

A guard is a function (class-based guards are deprecated as of Angular 15.2) that can return three different values:

  • true if we want to allow the user to proceed (then the navigation happens)
  • false if we want to prevent the user from proceeding (then the navigation doesn’t happen)
  • A UrlTree if we want to redirect the user to another component (usually a login component or an error component)

Sometimes, we want to ask a server about the user, which means that our guard is going to do asynchronous work. That’s fine because guards can return an Observable or a Promise of the above values, which means that a guard can return any of the six following types:

Any route can be protected by one or more guards. In the router config, we define an array of guards for each route as follows:

The above code means that in order to access the path /team/:id, a user has to satisfy the requirement of canActivateTeam, a guard function that returns one of the values documented above.

Standalone Application and Router config

With this daily post, let’s get back to the new Angular standalone features. So far, we have seen how to create standalone components, add dependencies, and lazy-loading of standalone components.

Since the primary goal of standalone components is to have less NgModules, what about creating an Angular application with no NgModule at all?

Enter the bootstrapApplication function (from @angular/platform-browser). All it needs is the root standalone AppComponent as a parameter:

And that’s it. No AppModule needed. Now you’re probably wondering: How to add some router config?

There’s a provideRouter function for that, along with several router utility functions to configure preloading, guards, error handling, and more:

Last but not least, if you need to use services from a third-party module and don’t want to import the other features of that module (components/pipes/directives), you can also do the following:

As you can see, standalone components have paved the way for many new function-based features (instead of classes/services), and we’ll see even more of those in the coming posts.