CHAPTER 6
Navigating through your application is a crucial part of a user experience, and Aurelia comes ready with a very powerful router. It takes a single Aurelia element to get your application ready to use the router. Let’s look at what is required to get your router set up:
Code Listing 93
<template> <router-view></router-view> </template> |
We see that we are using the router-view element. It performs all the heavy lifting with regard to responding when a route has changed. If you recall, we reviewed the configureRouter method in Chapter 4. If we examine the config.map function, we see that it takes in an array of RouteConfig objects. Each RouteConfig object represents a given route. Here are all the properties that make up the RouteConfig object:
As you can see from the properties, you have a lot of power with how you want to configure your routes. Let’s look at a typical configuration:
Code Listing 94
export class App { configureRouter(config, router) { config.title = 'Aurelia'; config.map([ { route: ['', 'home'], name: 'home', moduleId: './home', nav: true, title: 'Home' }, { route: 'blogs', name: 'blogs', moduleId: './blogs', nav: true, title: 'Blogs' }, { route: 'blogs/:id', name: 'blog-detail', moduleId: './blog-detail', nav: false, title: 'Blog Detail' } ]); this.router = router; } } |
In this example, we have defined three routes. The first route is our default route due to the presence of the empty string (‘’) as part of the match patterns for the route property. Also notice that we have identified a parameterized route for the blog-detail. The convention is a colon (:) followed by the name of the parameter. Besides parameterized routes, you can also specify wildcard routes using the asterisk (*) followed by the name of the parameter to represent the rest of the path. You will also need to provide an href entry in the route when you do this.
The moduleId is where Aurelia looks to find the view-model for activation. This can represent any folder structure if you wish to organize your view-models in a certain way. This is common in feature-driven folder structures. Note that we are not using the nav property for every route. By setting nav to false or omitting the property, we are specifying that we do not wish it to be part of the router navigation nav model that is used when generating our menus. Finally, title is what will be displayed in our menus from the router navigation nav model.
Sometimes it is necessary to perform business logic before or after we navigate to a given route. That is what pipelines bring to the table, and following is a breakdown of each:
So, if we would like to create an authorize step and add it to the pipeline, we would do something like the following:
Code Listing 95
import AuthorizeStep from './authorize-step'; export class App { configureRouter(config, router) { config.title = 'Aurelia'; config.addPipelineStep('authorize', AuthorizeStep); config.map([ { route: 'home', moduleId: './home', title: 'Home', settings: { roles: [] } }, { route: 'blogs', moduleId: './blogs', title: 'Blogs', settings: { roles: ['admin'] }, { route: 'blog/:id', moduleId: './blog-detail', title: 'Blog Detail', settings: { roles: ['admin'] } } ]); this.router = router; } } |
As you can see, we are importing the AuthorizeStep so that we can use it when we call the addPipelineStep function. Also notice that we are using the settings property and passing in some custom data that we will look for in the AuthorizeStep class.
Note: Make sure that you use the correct spelling when you pass in the first argument to the addPipelineStep.
Let’s now look at the AuthorizeStep class:
Code Listing 96
export class AuthorizeStep { run(navigationInstruction, next) { if (navigationInstruction.getAllInstructions() .some(i => i.config.settings.roles.indexOf('admin') !== -1)) { var isAdmin = /* insert logic to determine if user is admin here */ false; if (!isAdmin) { return next.cancel(new Redirect('home')); } } return next(); } } |
This is a very simple example, but I hope it gives you an idea of what you can do. We are interrogating the settings property of each of the routes and checking to see if the roles array contains a value of admin. If it does find a match, then we have a variable that would represent whether or not the current user is an admin or not. If the isAdmin is false, then we ignore the routing instruction and redirect back to the home screen.
If you’d like to learn more, please refer here.
As we saw from the pipelines, there are certain points in a screen lifecycle that we can tap into. Aurelia provides screens with the ability to influence the activation lifecycle. Let’s look at the hooks provided:
Each of these hooks is powerful and you will find a lot of value as you start to use them. A common example would be using the canDeactivate hook to ensure that the user isn’t trying to navigate away from a dirty screen, meaning they need to save their changes or finish an important action before they can navigate away from the screen.