In Aurelia 2, despite the framework itself being completely overhauled and rewritten, many aspects of the framework remain the same familiar Javascript framework many of us know and love. What is new is the router in v2, it works differently to v1 in many aspects.
The router can work a few different ways. The first being the new direct-routing functionality which allows you to route to components without having to write any route configuration code. I love the direct router, which you can read more about here in the official Aurelia 2 docs.
The second being component configured routing which is a mixture of direct routing, but allows you to override and define some router configuration settings inside of the components you are routing to. It allows you to name parameters and other aspects you might want to change, without really needing to write any configuration code.
The third (and focus of this article) is configured routing. If you come from an Aurelia 1 background or have worked with any other framework/library which most likely has a router that works off configuration, this would be the approach you would be most familiar with.
While I would recommend trying out the other routing options first, there are valid use-cases for configured routes. One of those being migrating Aurelia 1 applications to Aurelia 2, configured routing makes the most sense here and allows you to gradually port over Aurelia 1 routes to Aurelia 2 component-by-component.
Another use-case you might find yourself needing to meet is where it matters what the routes look like. When using the direct routing functionality or even the component configured routing, your URLs might look a little foreign to you like the following. http://localhost:9000/component(somevalue=github)
One thing to remember
You need to ensure all of your components are registered with Dependency Injection. I import my components inside of the view where the au-viewport
element is at the top which seems like the easiest place.
<import from="./components/profile"></import> <import from="./components/profiles"></import>
You can also opt to specify your dependencies on the customElement
definition, but it requires a lot more work to do it this way. Importing inside of the view is safe, fast and the easiest solution right now. There is talk of a @dependencies
decorator, but it might not be coming anytime soon (and it’s not guaranteed either).
Also, at the time of writing this, there are still some WIP router changes that have not been merged into the core package just yet. A decorator for defining routes called @routes
does exist, but is not merged. So, for the moment, you will need to use static routes
to define configured routes (which isn’t a big deal and the decorator will work the same).
Creating a simple route
To use configured routes, you simply need to define a static property on the viewport view-model (the view-model for the view that contains an au-viewport
element. If you used npx makes aurelia
to generate your application, you will have two files (one ending in .ts and another .html) my-app
which will contain a <au-viewport>
element pair.
import { Profile } from './components/profile'; import { ICustomElementViewModel } from 'aurelia'; export class MyApp implements ICustomElementViewModel { static routes = [ { path: 'profile/:id', id: 'profile', component: Profile } ]; }
In this simple example, we create a route using familiar routing syntax from Aurelia 1 and other frameworks to create a URL /profile/:id
where id
is a dynamic ID value passed into the component (this case, Profile
). For this example, we are not doing anything too crazy, just a basic route configuration object.
Optional route parameters
Just like the v1 router and other routers once again, you can specify optional route parameters which are ignored if they are not supplied in the URL.
import { Profile } from './components/profile'; import { ICustomElementViewModel } from 'aurelia'; export class MyApp implements ICustomElementViewModel { static routes = [ { path: 'profile/:id/:name?', id: 'profile', component: Profile } ]; }
By adding a question mark to the end of the parameter, it will become optional.
Adding a title to your route
To specify a title for the route, we can add in a title
property to our route configuration object and it will display in our browser.
import { Profile } from './components/profile'; import { ICustomElementViewModel } from 'aurelia'; export class MyApp implements ICustomElementViewModel { static routes = [ { path: 'profile/:id', id: 'profile', component: Profile, title: 'My Profile' } ]; }
Passing data through routes
We are still only scratching the surface here. What if you want to pass some data through with your routes? If you worked with Aurelia 1, you would be familiar with settings
in Aurelia 2’s router, it’s data
. Same concept, a different name that makes way more sense.
import { Profile } from './components/profile'; import { ICustomElementViewModel } from 'aurelia'; export class MyApp implements ICustomElementViewModel { static routes = [ { path: 'profile/:id', id: 'profile', component: Profile, data: { requiredRoles: ['admin', 'author'] } } ]; }
This theoretical example sees us adding a requiredRoles
array to the route, this will allow us to do permissions based checks on a per-route basis which is something I have done numerous times with Aurelia 1.
Route instructions (specify viewports and whatnot)
If you are working with multiple viewports in your application, say you might have a viewport for the footer, another for the head and perhaps one for the sidebar and want to load different content into those, the instructions
property that takes an array has you covered.
import { Profile } from './components/profile'; import { ICustomElementViewModel } from 'aurelia'; export class MyApp implements ICustomElementViewModel { static routes = [ { path: 'profile/:id', id: 'profile', instructions: [ { component: Profile, viewport: 'main' } ] } ]; }
This powerful feature allows you to not only specify singular route instructions (which you would never use with this approach), you can have one route theoretically contain multiple instructions, allowing you to render different components into different viewports on a singular route.
If you had a profile page, maybe you have a dynamic sidebar which you inject some ads into and other components for widgets specific to a users profile.
import { Profile } from './components/profile'; import { ProfileSidebar } from './components/profile-sidebar'; import { ICustomElementViewModel } from 'aurelia'; export class MyApp implements ICustomElementViewModel { static routes = [ { path: 'profile/:id', id: 'profile', instructions: [ { component: Profile, viewport: 'main' }, { component: ProfileSidebar, viewport: 'profile-sidebar' } ] } ]; }
By adding in an additional viewport instruction, we are now composing the element ProfileSidebar
into a viewport with the name profile-sidebar
. Cool, huh?
Thanks for the information on V2. It is very exciting to see the new release and try to figure out how things have changed. I am looking through your examples and see all the new features in the routing options to define the routes, but I do not see much online with respect to utilizing the routes. It appears that the preferred new method is the load method. In V1 I utilize the route-href attribute so that I can pass the needed parameters and have the actual url be generated, this is preferred in case I were ever to change the actual pattern as well as seems easier to provide the values than ensue that there are no typos in the route (when outputting the actual href to the route). Is this no longer an option? It seems to be better as it will also add extra properties to the querystring which are also retrievable on activate. I hope that this is not being written out of the framework as I really appreciate this feature.
Hello Mr. Dwayne!
I’m trying to upgrade to v2 alpha 40, but I’m running into some router issues.
Does this post still apply too the latest version of the alpha release?
Thanks!
–Steve