Configuring routes
Learn about configuring routes in Router-Lite.
The router takes your routing instructions and matches the URL to one of the configured Routes to determine which components to render. To register routes you can either use the @route
decorator or you can use the static routes
property to register one or more routes in your application. This section describes the route configuration options in details.
Route configuration basics
The routing configuration syntax for router-lite is similar to that of other routers you might have worked with before. If you have worked with Express.js routing, then the syntax will be very familiar to you.
A route is an object containing a few required properties that tell the router what component to render, what URL it should match on and other route-specific configuration options.
The most usual case of defining a route configuration is by specifying the path
and the component
properties. The idea is to use the path
property to define a pattern, which when seen in the URL path, the view model defined using the component
property is activated by the router-lite. Simply put, a routing configuration is a mapping between one or more path patterns to components. Below is the simple example (from the getting started section) of this.
For the example above, when the router-lite sees either the path /
or /home
, it loads the Home
component and if it sees the /about
path it loads the About
component.
Note that you can map multiple paths to a single component. Although these paths can be thought of as aliases, multiple paths, in combination with path parameters gets interesting. Another way of creating aliases is to use the redirectTo
configuration option.
Note that the example above uses the @route
decorator. In case you cannot use the decorator, you can use the static properties instead. The example shown above can be rewritten as follows.
As the re-written example shows, you can convert the properties in the options object used for the @route
decorator into static
properties in the view model class.
Apart from the static API including the @route
decorator, there is also an instance-level hook named getRouteConfig
that you can use to configure your routes. This is shown in the example below.
See this in action below.
Note that the hook is also supplied with a parent route configuration, and the new route node. These values can be nullable; for example, for root node there is no parent route configuration.
The getRouteConfig
can also be async
. This is shown in the example below.
See this in action below.
path
and parameters
path
and parametersThe path defines one or more patterns, which are used by the router-lite to evaluate whether or not an URL matches a route or not. A path can be either a static string (empty string is also allowed, and is considered as the default route) without any additional dynamic parts in it, or it can contain parameters. The paths defined on every routing hierarchy (note that routing configurations can be hierarchical) must be unique.
Required parameters
Required parameters are prefixed with a colon. The following example shows how to use a required parameter in the path
.
When a given URL matches one such route, the parameter value is made available in the canLoad
, and load
routing hooks.
Note that the value of the id
parameter as defined in the route configuration (:id
) is available via the params.id
. Check out the live example to see this in action.
Optional parameters
Optional parameters start with a colon and end with a question mark. The following example shows how to use an optional parameter in the path
.
In the example, shown above, the Product
component is loaded when the router-lite sees paths like /product
or /product/some-id
, that is irrespective of a value for the id
parameter. You can see the live example below.
Note that there is an additional link added to the products.html
to fetch a random product.
As the id
parameter is optional, even without a value for the id
parameter, clicking the link loads the Product
component. Depending on whether or not there is a value present for the id
parameter, the Product
component generates a random id and loads that.
Wildcard parameters
The wildcard parameters, start with an asterisk instead of a colon, act as a catch-all, capturing everything provided after it. The following example shows how to use a wildcard parameter in the path
.
In the example, shown above, the Product
component is loaded when the router-lite sees paths like /product/some-id
or /product/some-id/foo/bar
. You can see the live example below.
The example utilizes a wildcard parameter named rest
, and when the value of rest
is 'image'
, an image for the product is shown. To this end, the canLoad
hook of the Product
view-model reads the rest
parameter.
Constrained parameters
Any required and optional parameters can be constrained by using a regular expression.
The following example shows how to use a wildcard parameter in the path
.
Note that the syntax to define a parameter constraint is as follows.
The example above shows that the Product
component is loaded when the router-lite sees paths like /product/123
, but not /product/abc
.
You can see the live example below.
Note that ^
and $
implies that the value of complete path segment must match the regular expression. You are however free to choose any regular expression that fits your needs. For example, 'product/:id{{^\\d+}}'
is also a valid constraint and will match paths like /product/123
, /product/123abc
etc.
Setting the title
You can configure the title for the routes while you are configuring the routes. The title can be configured in the root level, as well as in the individual route level. This can be seen in the following example using the @route
decorator.
If you prefer using the static routes
property, the title can be set using a static title
property in the class. The following example has exactly the same effect as of the previous example.
With this configuration in place, the default-built title will be Home | Aurelia
when user is navigated to /
or /home
route. That is, the titles of the child routes precedes the base title. You can customize this default behavior by using a custom buildTitle
function when customizing the router configuration.
Note that, instead of a string, a function can also be used for title
to lazily set the title.
Redirect to another path
By specifying the redirectTo
property on our route, we can create route aliases. These allow us to redirect to other routes. In the following example, we redirect our default route to the home
page and the about-us
to about
page.
You can see this action below.
Note that redirection also works when there are multiple paths/aliases defined for the same component.
You can see this action below.
You can use route parameters for redirectTo
. The following example shows that the parameters from the about-us
path is rearranged to the about
path.
You can see this action below.
Fallback: redirecting the unknown path
We can instruct the router-lite to redirect the users to a different configured path, whenever it sees any unknown/un-configured paths. To this end, we can use the fallback
configuration option. Following example shows how to use this configuration option.
As the example shows, the fallback
is configured as follows.
There is a custom element, named NotFound
, which is meant to be loaded when any unknown/un-configured route is encountered. As you can see in the above example, clicking the "Foo" link that is with un-configured href
, leads to the NotFound
view.
It is recommended that you configure a fallback
at the root to handle the navigation to un-configured routes gracefully.
Another way of defining the fallback
is to use the route-id
. The following example demonstrates this behavior, where the NotFound
view can be reached via multiple aliases, and instead of choosing one of these aliases the route-id
is used to refer the route.
The name of the custom element, meant to be displayed for any un-configured route can also be used to define fallback
. The following example demonstrates this behavior, where not-found
, the name of custom element NotFound
, is used to refer the route.
An important point to note here is that when you are using the custom element name as fallback, you need to ensure that the custom element is registered to the DI container. Note that in the example above, the NotFound
component is registered to the DI container in main.ts
.
A fallback
defined on parent is inherited by the children (to know more about hierarchical routing configuration, refer the documentation). However, every child can override the fallback as needed. The following example demonstrate this. The root has two sibling viewports and two children components can be loaded into each of those by clicking the link. Every child defines their own child routing configuration. The root defines a fallback
and one of the children overrides the fallback
by defining one of its' own. With this configuration in place, when navigation to a un-configured route ('Foo') is attempted for each children, one loads the overridden version whereas the other loads the fallback inherited from the parent (in this case the root).
A function can be used for fallback
. The function takes the following signature.
An example can look like below, where the example redirects the user to NF1
component if an attempt to load a path /foo
is made. Every other attempt to load an unknown path is results loading the NF2
component.
You can also see this in action below.
You can also use non-string fallbacks. For example, you can use a class as the value for fallback
; such as fallback: NotFound
. Or, if you are using a function, you choose to return a class instead of returning a string. These combinations are also supported by router-lite.
Case sensitive routes
Routes can be marked as case-sensitive in the configuration, allowing the navigation to the component only when the case matches exactly the configured path. See the example below where the navigation to the "about" page is only successful when the casing matches.
Thus, only an attempt to the /AbOuT
path loads the About
component; any attempt with a different casing is navigated to the fallback
. See this in action below.
Advanced route configuration options
There are few other routing configuration which aren't discussed above. Our assumption is that these options are more involved and might not be used that often. Moreover, to understand the utility of these options fully, knowledge of other parts of the route would be beneficial. Therefore, this section only briefly introduces these options providing links to the sections with detailed examples.
id
— The unique ID for this route. The router-lite implicitly generates aid
for a given route, if an explicit value for this property is missing. Although this is not really an advanced property, due to the fact that a route can be uniquely identified withid
, it can be used in many interesting ways. For example, this can be used to generate thehref
s in the view when using theload
custom attribute or using theRouter#load
API. Using this property is also very convenient when there are multiple aliases for a single route, and we need a unique way to refer to this route.transitionPlan
— How to behave when the currently active component is scheduled to be loaded again in the same viewport. For more details, please refer the documentation.viewport
— The name of the viewport this component should be loaded into. This demands a full fledged documentation of its own. Refer to the viewport documentation for more details.data
— Any custom data that should be accessible to matched components or hooks. The value of this configuration property must be an object and the object can take any shape (that is there is no pre-defined interface/class for this object). A typical use-case for thedata
property is to define the permissions, required by the users, when they attempt to navigate to this route. Refer an example of this.nav
- Set this flag tofalse
(default value istrue
), to instruct the router not to add the route to the navigation model. This is typically useful to exclude routes from the public navigation menu.
Specifying component
Before finishing the section on the route configuration, we need to discuss one last topic for completeness, and that is how many different ways you can configure the component
. Throughout various examples so far we have seen that components are configured by importing and using those in the routing configuration. However, there are many other ways in which the components can be configured. This section discusses those.
Using inline import()
import()
Components can be configured using the import()
or dynamic import. Instead of statically importing the components, those can be imported using import()
-syntax, as the example shows below.
You can see this in action below.
If you are using TypeScript, ensure that the module
property set to esnext
in your tsconfig.json
to support inline import statements.
Using the name
Components can be configured using only the custom-element name of the component.
However, when configuring the route this way, you need to register the components to the DI.
You can see this configuration in action below.
Using a function returning the class
Components can be configured using a function that returns a class.
You can see this configuration in action below.
Using custom element definition
Components can be configured using custom element definition.
You can see this configuration in action below.
Using custom element instance
Components can be configured using custom element instance.
You can see this configuration in action below.
Using classes as routes
Using router-lite it is also possible to use the routed view model classes directly as routes configuration. While doing so, if no paths have been explicitly configured for the components, the custom element name and aliases can be used as routing instructions. The following example demonstrates that the C1
and C2
classes are used directly as the child routes for the Root
.
The example above implies that router.load('c-1')
, or router.load('c-a')
and router.load('c-2')
, router.load('c-two')
will load the C1
and C2
respectively.
To know more about the router API refer this section.
Distributed routing configurations
The examples discussed so far demonstrate the classic use-cases of route configurations where the parents define the child routes. Another aspect of these examples are that all the route configurations are centralized on the parent component. This section provides some examples where that configuration is distributed across different components.
We start by noting that every component can define its own path. This is shown in the following example.
The example shows that both Home
and About
uses the @route
decorator to define their own paths. This reduces the child-route configuration for MyApp
to @route({ routes: [Home, About] })
. The example can be seen in action below.
Note that other properties of route configuration can also be used in this way.
The previous example demonstrates that the Home
and About
components define the title
for themselves. The example can be seen in action below.
While adapting to distributes routing configuration, the parent can still override the configuration for its children. This makes sense, because even if a component defines its own path
, title
etc. the parent may choose to reach (route) the component via a different path or display a different title when the component is loaded. This is shown below, where the MyApp
overrides the routing configurations defined by About
.
This can be seen in action below.
You can also use the @route
decorator and the getRouteConfig
together.
This can be seen in action below.
The advantage of this kind of distributed configuration is that the routing configuration of every component is defined by every component itself, thereby encouraging encapsulation, leaving the routing configuration at the parent level to merely listing out its child components. On the other hand, highly distributed route configuration may prevent easy overview of the configured routes. That's the trade-off. Feel free to mix and match as per your need and aesthetics.
Last updated