Skip to content

Commit

Permalink
GitBook: [aurelia#130] Routing improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
Vheissu authored and gitbook-bot committed Feb 25, 2022
1 parent f74f61c commit 552f8db
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 279 deletions.
4 changes: 3 additions & 1 deletion docs/user-docs/TOC.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,16 @@
## Developer Guides

* [Routing](developer-guides/routing/README.md)
* [Routing fundamentals](developer-guides/routing/common-routing-tasks.md)
* [Router configuration](developer-guides/routing/router-configuration.md)
* [Creating routes](developer-guides/routing/creating-routes.md)
* [Routing lifecycle](developer-guides/routing/routing-lifecycle.md)
* [Viewports](developer-guides/routing/viewports.md)
* [Redirecting](developer-guides/routing/redirecting.md)
* [Navigating](developer-guides/routing/navigating.md)
* [Route hooks](developer-guides/routing/router-hooks.md)
* [Route events](developer-guides/routing/route-events.md)
* [Direct Routing](developer-guides/routing/direct-routing.md)
* [Routing fundamentals](developer-guides/routing/common-routing-tasks.md)
* [Validation](developer-guides/validation/README.md)
* [Plugin configuration](developer-guides/validation/registering-the-plugin.md)
* [Defining & Customizing Rules](developer-guides/validation/defining-rules.md)
Expand Down
123 changes: 13 additions & 110 deletions docs/user-docs/developer-guides/routing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@

## Getting started

Aurelia being a fully-featured framework comes with a router package ready to use in the framework.
Aurelia being a fully-featured framework comes with a router package ready to use in the framework. To register the plugin in your application, you can pass in the router object to the `register` method inside of the file containing your Aurelia initialization code. 

To register the plugin in your application, you can pass in the router object to the `register` method inside of the file containing your Aurelia initialization code. 
{% hint style="success" %}
Looking for a shortcut? If you generate a new Aurelia application using `npx makes aurelia` and choose routing, you can skip over this getting started section as we talk about code that is automatically added in for you as part of the scaffolding process.
{% endhint %}

We import the `RouterConfiguration` class from the `aurelia` package, which allows us to register our router and change configuration settings.

This file is generated from the `npx makes aurelia` scaffolding tool and is found in `src/main.ts`

{% code title="main.ts" %}
```typescript
import Aurelia, { RouterConfiguration } from 'aurelia';

Expand All @@ -18,9 +21,14 @@ Aurelia
.app(component)
.start();
```
{% endcode %}

The `RouterConfiguration` object is highly configurable and allows us to change how routing works in our Aurelia applications. It will use some default settings if you don't change anything (like we have done). By default, the router will assume you are using pushState routing.

{% hint style="info" %}
A scaffolded Aurelia application using `makes` and routing selected will automatically add in router configuration for you. The code above is taken from a newly generated Aurelia application and shown for reference.
{% endhint %}

### Create a viewport

After registering the router plugin, we need to add a viewport element to the default root component. If you scaffolded your application using Makes, then your root component by default is `my-app.ts` and `my-app.html`.
Expand All @@ -33,115 +41,10 @@ Inside of `my-app.html` you can add the following to get you started:

We will get into the specifics of the `<au-viewport>` element later on. Right now, all you need is this one simple element in the same view as the accompanying view model that contains the routes.

To learn more about configuring the viewport, please see the router docs on configuring the viewport in the [viewports section](viewports.md).

## Changing the router mode (hash and pushState routing)

If you do not provide any configuration value, the default as we saw above is pushState routing. If you prefer the hash to be used, you can enable this like so:

```typescript
import Aurelia, { RouterConfiguration } from 'aurelia';

Aurelia
.register(RouterConfiguration.customize({ useUrlFragmentHash: true }))
.app(component)
.start();
```

By calling the `customize` method, you can supply a configuration object containing the property `useUrlFragmentHash` and supplying a boolean value. If you supply `true` this will enable hash mode. The default is `false`.

If you are working with pushState routing, you will need a base HREF value in the head of your document. The scaffolded application from the CLI includes this in the `index.html` file, but if you're starting from scratch or building within an existing application you need to be aware of this.

```html
<head>
<base href="/">
</head>
```

{% hint style="warning" %}
PushState requires server-side support. This configuration is different depending on your server setup. For example, if you are using Webpack DevServer, you'll want to set the `devServer` `historyApiFallback` option to `true`. If you are using ASP.NET Core, you'll want to call `routes.MapSpaFallbackRoute` in your startup code. See your preferred server technology's documentation for more information on how to allow 404s to be handled on the client with push state.
{% endhint %}

## Router Configuration options

The `customize` method on the `RouterConfiguration` object can be used to set numerous router settings besides the `useUrlFragmentHash` value.

{% hint style="info" %}
While router hooks can be configured on a global basis from within `customize` those are covered in their own dedicated section.
Like router configuration, using `makes` will automatically add in a `au-viewport` element to `my-app.html` if you choose routing as part of the scaffolding decision process.
{% endhint %}

### Styling Active Router Links

A common scenario is styling an active router link with styling to signify that the link is active, such as making the text bold. The `load` attribute has a bindable property named `active` which you can bind to a property on your view-model to use for conditionally applying a class:

```css
.active {
font-weight: bold;
}
```

```html
<a active.class="_settings" load="route:settings; active.bind:_settings">
Settings
</a>
```

The `active` property is a boolean value that we bind to. In this example, we use an underscore to signify this is a private property.

{% hint style="info" %}
You do not need to explicitly declare this property in your view model since it is a from-view binding. The underscore prefix of \_settings has no special meaning to the framework, it is just a common convention for private properties which can make sense for properties that are not explicitly declared in the view model.
{% hint style="success" %}
To learn more about configuring the viewport, please see the router docs on configuring the viewport in the [viewports section](viewports.md)
{% endhint %}

### Configuring route markup parsing using useHref

The `useHref` configuration setting is something that all developers working with routing in Aurelia need to be aware of. By default, the router will allow you to use both `href` as well as `load` for specifying routes.

Where this can get you into trouble is external links, mailto links and other types of links that do not route. A simple example looks like this:

```html
<a href="mailto:[email protected]">Email Me</a>
```

This seemingly innocent and common scenario by default will trigger the router and will cause an error in the console.

You have two options when it comes to working with external links. You can specify the link as external using the `external` attribute.

```html
<a href="mailto:[email protected]" external>Email Me</a>
```

Or, you can set `useHref` to `false` and only ever use the `load` attribute for routes.

```typescript
import Aurelia, { RouterConfiguration } from 'aurelia';

Aurelia
.register(RouterConfiguration.customize({
useHref: false
}))
.app(component)
.start();
```

### Configuring the same URL strategy

In some scenarios, the same route may be used more than once. On a global level, you can configure the same URL strategy to either be `replace` or `ignore`. The default value for this is `ignore`.

```typescript
import Aurelia, { RouterConfiguration } from 'aurelia';

Aurelia
.register(RouterConfiguration.customize({
sameUrlStrategy: 'replace'
}))
.app(component)
.start();
```

### Configuring the route swap order

The `swapStrategy` configuration value determines how contents are swapped in a viewport when transitioning. The default value for this setting is `sequential-`remove`-first` — however, in some instances, you might want to change this depending on the type of data you are working with or how your routes are loaded.

* `sequential-add-first`
* `sequential-remove-first`
* `parallel-remove-first`
22 changes: 22 additions & 0 deletions docs/user-docs/developer-guides/routing/common-routing-tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,28 @@ This section details common scenarios and tasks using the router in your Aurelia

It is highly recommended that you familiarize yourself with other parts of the router documentation before consulting this section, as we will introduce concepts that you might not be familiar with just yet that are mentioned in other sections of the router documentation.

## Styling Active Router Links

A common scenario is styling an active router link with styling to signify that the link is active, such as making the text bold. The `load` attribute has a bindable property named `active` which you can bind to a property on your view-model to use for conditionally applying a class:

```css
.active {
font-weight: bold;
}
```

```html
<a active.class="_settings" load="route:settings; active.bind:_settings">
Settings
</a>
```

The `active` property is a boolean value that we bind to. In this example, we use an underscore to signify this is a private property.

{% hint style="info" %}
You do not need to explicitly declare this property in your view model since it is a from-view binding. The underscore prefix of \_settings has no special meaning to the framework, it is just a common convention for private properties which can make sense for properties that are not explicitly declared in the view model.
{% endhint %}

## Setting The Title

While you would in many cases set the title of a route in your route configuration object using the `title` property, sometimes you want the ability to specify the title property from within the routed component itself.
Expand Down
175 changes: 8 additions & 167 deletions docs/user-docs/developer-guides/routing/direct-routing.md
Original file line number Diff line number Diff line change
@@ -1,176 +1,17 @@
---
description: >-
How to leverage direct routing in your Aurelia applications using the
convention-based direct router feature.
Learn about an alternative routing option available in the Aurelia router that
offers zero-configuration routing.
---

# Direct routing
# Direct Routing

{% hint style="info" %}
`Please note that we currently have an interim router implementation and that some (minor) changes to application code might be required when the original router is added back in.`
{% endhint %}
The Aurelia router supports different ways of routing. In sections such as Creating Routes, we talk about configured routes, which require you to map out your routes ahead of time and have an understanding of how things are mapped. With direct routing, the router works on the basis of zero-configuration routing.

Aurelia is known for its conventions-based approach to building applications. It provides you with a set of sane defaults and ways of doing certain things in your app, which help save time and make your life easier. The router in Aurelia 2 is no exception.
It might sound like some kind of developer-hype, but zero-configuration routing in the form of direct routing allows you to route in your application without configuring your routes. Think of the direct router as a form of dynamic composition for routing.

{% hint style="success" %}
**What you will learn in this section**
By default, you don't need to tell the router you want to use direct routing. Instead of referencing route names or paths, you reference component names.

* What direct routing is
* How to create parameter-less routes
* How to create routes with parameters
* How to pass data through routes
* How to name parameters
{% endhint %}

## What Is Direct Routing?

To put it in simple terms, direct routing is routing without route configuration. Unlike other routers you might be familiar with, you do not need to specify your routes upfront in code. The direct routing functionality works for all kinds of routing from standard routes to routes with parameters, child routing and more.

### How it works

You start off by registering the plugin in your app, you add in an `<au-viewport>` element where your routes will be displayed. Then using the `load` attribute on your links, you can tell the router to render a specific component.

Components which have been globally registered inside the `register` method, or imported inside of the view can be rendered through the router.

## Direct routing example

As you will see, the direct routing approach requires no configuration. We import our component and then reference it by name inside of the `load` attribute.

{% tabs %}
{% tab title="my-app.html" %}
```markup
<import from="./test-component.html"></import>
<ul>
<li><a load="test-component">Test Component</a></li>
</ul>
<au-viewport></au-viewport>
```
{% endtab %}

{% tab title="test-component.html" %}
```markup
<h1>Hello world, I'm a test component.</h1>
```
{% endtab %}
{% endtabs %}

The `load` attribute on our link denotes that this link is to navigate to a component using the router. Inside of the `load` attribute, we pass in the name of the component \(without any file extension\). As you can see, HTML only components are supported by the router.

## Routes with parameters

The simple example above shows you how to render a component using the router, and now we are going to introduce support for parameters. A parameter is a dynamic value in your route which can be accessed inside of the routed component. For example, this might be a product ID or a category name.

To access parameters from the route, we can get those from the router lifecycle hook called `load` which also supports promises and can be asynchronous.

{% tabs %}
{% tab title="my-app.html" %}
```markup
<import from="./test-component"></import>
<ul>
<li><a load="test-component(hello)">Test Component</a></li>
</ul>
<au-viewport></au-viewport>
```
{% endtab %}

{% tab title="test-component.ts" %}
```typescript
import { IRouteViewModel } from 'aurelia';

export class TestComponent implements IRouteViewModel {
load(parameters) {
console.log(parameters); // Should display {0: "hello"} in the browser developer tools console
}
}
```
{% endtab %}

{% tab title="test-component.html" %}
```markup
<h1>Hello world, I'm a test component.</h1>
```
{% endtab %}
{% endtabs %}

In this example, we are not telling the router the name of our parameters. By default, the router will pass an object keyed by index \(starting at 0\) for unnamed parameters. To access the value being given to our test component, we would reference it using `parameters['0']` which would contain `1` as the value.

### **Inline named route parameters**

You can name your route parameters inline by specifying the name inside of the `load` attribute on the component.

{% tabs %}
{% tab title="my-app.html" %}
```markup
<import from="./test-component"></import>
<ul>
<li><a load="test-component(named=hello)">Test Component</a></li>
</ul>
<au-viewport></au-viewport>
```
{% endtab %}

{% tab title="test-component.ts" %}
```typescript
import { IRouteViewModel } from 'aurelia';

export class TestComponent implements IRouteViewModel {
load(parameters) {
console.log(parameters); // Should display {named: "hello"} in the browser developer tools console
}
}
```
{% endtab %}

{% tab title="test-component.html" %}
```markup
<h1>Hello world, I'm a test component.</h1>
```
{% endtab %}
{% endtabs %}

### **Named route parameters**

It is recommended that unless you do not know the names of the parameters, that you supply the names inside of your routed component using the static class property `parameters` which accepts an array of strings corresponding to parameters in your route.

While you can name them inline, specifying them inside of your component makes it easier for other people working in your codebase to determine how the component work.

{% tabs %}
{% tab title="my-app.html" %}
```markup
<import from="./test-component"></import>
<ul>
<li><a load="test-component(hello)">Test Component</a></li>
</ul>
<au-viewport></au-viewport>
```
{% endtab %}

{% tab title="test-component.ts" %}
```typescript
import { IRouteViewModel } from 'aurelia';

export class TestComponent implements IRouteViewModel {
static parameters = ['id'];

load(parameters) {
console.log(parameters); // Should display {id: "hello"} in the browser developer tools console
}
}
```
{% endtab %}

{% tab title="test-component.html" %}
```markup
<h1>Hello world, I'm a test component.</h1>
```
{% endtab %}
{% endtabs %}
## Direct Routing explained in code

A picture is worth a thousand words, so let's go through the makeup of a direct router-based Aurelia application. Fortunately, for us, by choosing "direct routing" when prompted via `npx makes aurelia` we will have an application that uses direct routing by default.
Loading

0 comments on commit 552f8db

Please sign in to comment.