left-icon

Aurelia Succinctly®
by Matthew Duffield

Previous
Chapter

of
A
A
A

CHAPTER 6

Routing

Routing


Overview

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:

  • route–The route pattern to match against incoming URL fragments, or an array of patterns.
  • name–A unique name for the route that may be used to identify when generating URL fragments.
  • moduleId–The module ID of the view-model that should be activated for this route.
  • redirect–A URL fragment to redirect to when this route is matched.
  • navigationStrategy–A function that can be used to dynamically select the module or modules to activate. The function is passed the current NavigationInstruction, and should configure instruction.config with the desired moduleId, viewPorts, or redirect.
  • viewPorts–The view ports to target when activating this route. If unspecified, the target module ID is loaded into the default viewport (the viewport with name default). The viewPorts object should have keys whose property names correspond to names used by <router-view> elements. The values should be objects specifying the module ID to load into that view port.
  • nav–When specified, this route will be included in the Router.navigation nav model. Useful for dynamically generating menus or other navigation elements. When a number is specified, that value will be used as a sort order.
  • href–The URL fragment to use in nav models. If unspecified, the RouteConfig.route will be used. However, if the RouteConfig.route contains dynamic segments, this property must be specified.
  • generationUsesHref–Indicates that when route generation is done for this route, it should just take the literal value of the href property.
  • title–The document title to set when this route is active.
  • settings–Arbitrary data to attach to the route. This can be used to attach custom data needed by components like pipeline steps and activated modules.
  • navModel–The navigation model for storing and interacting with the route’s navigation settings.
  • caseSensitive–When true is specified, this route will be case sensitive.
  • activationStrategy–Add to specify an activation strategy if it is always the same and you do not want that to be in your view-model code. Available values are replace and invoke-lifecycle.

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.

Pipelines

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:

  • authorize–Called between loading the route’s step and calling the route view-model’s canActivate function, if defined.
  • preActivate–Called between the route view-model’s canActivate function and the previous route view-model’s deactivate function, if defined.
  • preRender–Called between the route view-model’s activate function and before the component is rendered or composed.
  • postRender–Called after the component has been rendered or composed.

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.

Screen lifecycle

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:

  • canActivate(params, routeConfig, navigationInstruction)–This hook allows you to control whether or not your view-model can be navigated to. You can return a Boolean value, a promise for a Boolean value, or a navigation command.
  • activate(params, routeConfig, navigationInstruction)–This hook allows you to perform custom logic before your view-model is displayed. You can optionally return a promise so that the router will wait to bind and attach the view until your promise returns.
  • canDeactivate()–This hook allows you to control whether or not the router can navigate away from your view-model. You can return a Boolean value, a promise for a Boolean value, or a navigation command.
  • deactivate()–This hook allows you to perform custom logic when your view-model is being navigated away from. You can optionally return a promise so that the router will wait until after the promise returns.

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.

Scroll To Top
Disclaimer
DISCLAIMER: Web reader is currently in beta. Please report any issues through our support system. PDF and Kindle format files are also available for download.

Previous

Next



You are one step away from downloading ebooks from the Succinctly® series premier collection!
A confirmation has been sent to your email address. Please check and confirm your email subscription to complete the download.