@lightningjs/sdk
Version:
The Lightning-SDK helps you build great Lightning-based TV apps!
398 lines (295 loc) • 11 kB
Markdown
# Router Configuration
The Router plugin can be configured by passing a *configuration object* to the `Router.startRouter()` method. This method is typically called in the `_setup`[lifecycle event](../../../lightning-core-reference/Components/LifecycleEvents.md) in **App.js**.
The configuration object can contain five different *keys*, each of which is described below:
* [root](#root)
* [boot](#boot)
* [beforeEachRoute](#beforeeachroute)
* [afterEachRoute](#aftereachroute)
* [routes](#routes)
> It is recommended to specify the Router configuration in a separate file: **src/routes.js**.
## Keys
### root
The `root` key indicates which route path must be used as *entry point* of your App if *no* location hash is specified
in the URL.
The value of `root` should be a *String*, or a *function* that returns a *Promise* that resolves to a String.
The value must match the *path* of one of the defined routes.
Typically, you either specify the path to a **Splash** or **Home** page as `root`:
```js
import { Splash } from './pages';
export default {
root: 'splash',
routes: [
{
path: 'splash',
component: Splash
},
]
}
```
or you specify a function:
```js
export default {
root: () => {
return new Promise((resolve) => {
if(authenticated) {
resolve('browse')
}else{
resolve('login')
}
})
}
}
```
In the examples above, if you open your App, the Router plugin navigates to `localhost:8080#splash` (where the port '8080' serves as an example) and subsequently displays the **Splash** page.
### boot
The `boot` key provides the ability to execute functionality *before* the Router loads the first page. For example, this key can be applied to obtain API tokens.
If so required, you can specify a *function* in the `boot` key of the configuration object. This function must return a *Promise*. If the Promise resolves, the Router initiates the navigation process.
The `boot` function is not only executed when you open the root of your App, but is also invoked when you open
a [deeplinked](deeplinking.md) location in the App.
```js
export default {
boot: () => {
return new Promise(resolve => {
Api.getToken().then(() => {
resolve()
})
})
},
routes: [...]
}
```
The `querystring` (`qs`) is passed as an *object*.
For example, if you point the browser to: `localhost:8080#splash?deviceId=1801&partnerId=145`, the corresponding code looks like this:
```js
export default {
boot: (qs) => {
// qs => { deviceId: '1801', partnerId: '145' }
return Promise.resolve()
}
}
```
### beforeEachRoute
The `beforeEachRoute` key is a global hook that is invoked right after starting a `navigate` to a route.
Based on the `from` and `to` parameters that are passed by the Router to the hook, you can decide to *continue*, *stop* or *redirect* the `navigate`.
The hook must resolve to a *Promise*. If it resolves to `true`, the Router continues the process. If it resolves to `false`, the process is aborted.
```js
{
...
routes:[...],
beforeEachRoute: (from, to)=>{
return new Promise((resolve)=>{
if(to === "home/account" && auth){
resolve(true)
}
})
}
}
```
You can also redirect the `navigate` by returning a *String*. The Router will then try to navigate to the provided hash.
```js
{
...
routes:[...],
beforeEachRoute: async (from, to)=>{
if(to === "play/live/123" && !auth){
return "account/create";
}
}
}
```
If you want to pass parameters, the hook must return an *object*:
```js
{
...
routes:[...],
beforeEachRoute: async (from, to)=>{
if(to === "play/live/123" && !auth){
return {
path:"account/create",
params:{
msg: "Not authenticated",
pageFrom: from
}
}
}
}
}
```
> See [Navigation](navigation.md) for more information about the parameters that are passed to the page.
## afterEachRoute
Is a global hook that will be called after every successful `navigate()` request. The parameter is the resolved
request object.
```js
{
...
routes:[...],
afterEachRoute: (request)=>{
updateAnalytics("loaded", request.hash)
}
}
```
### routes
The `routes` key is an Array of route definition items. Each item represents a route path that the App should listen to. It specifies which Page component should be displayed when that route is hit.
Although you can define your `routes` object directly inside your **App.js**, it is recommended to specify your routes in a separate **routes.js** file. For example:
```js
// file: src/routes.js
import { Home, Browse } from './pages';
export default {
routes: [
{
path: 'home',
component: Home
},
{
path: 'home/browse/adventure',
component: Browse
}
]
}
```
## Dynamic Routes
So far, we have only specified *static* route paths (for example, `home/browse/adventure`). But the Router plugin also supports *dynamic* routes.
You can make a route part dynamic by prefixing it with `:` as shown in the following example:
```js
{
path: 'player/:assetId/:playlistId',
component: Player
}
```
For example, this route now matches `localhost:8080#player/27/286`. It also provides the data from the specific route (i.e., `assetId` and
`playlistId`).
## Accessing Data From Route Components
If you [navigate](#navigation-helper) to: `127.0.0.1:8080/#player/14728/38101`
the router will add the properties `.assetId = 14728` and `.playlistId = 38101` to the params property of the instance of the *Player* `Component`.
You can also use [setters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set) to execute logic when the properties are being set.
```js
class Player extends Lightning.Component {
static _template(){
return {...}
}
set params(args){
// args.assetId === 14728 && args.playlistId === 38101
}
}
```
## Using Regular Expressions in Routes
The Router plugin has built-in *regular expression support*, so you can add patterns to your route to have it matched with certain combinations of characters.
You do this by adding `${PATTERN/MODIFIERS}` after the dynamic name. For example:
```js
// this will match #player/1493847
// but will fail on #player/ah26134
{
path: 'player/:playlistId${/[0-9]{3,8}/i}',
component: Player
}
```
## Component Property
The `component` property can be a *Lightning Component* (i.e., a class that extends the `Lightning.Component`) or a *function* that returns a [dynamic import](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#Dynamic_Imports). For example:
```js
// component
{
path: 'home/browse/adventure',
component: Browse
}
```
```js
// dynamic import
{
path: 'home/browse/adventure',
component: ()=>{
return import("../pages/browse.js")
}
}
```
## Router Hooks
Besides specifying which component (for example, a page component) must be loaded for each route, you can also bind a *callback function* to a route via the `hook` function. This function is executed when the specific route is hit.
The *first* argument of the `hook` function is a reference to the `application`.
Any data that are provided via route parts, are passed in an object in the *second* argument. For example:
```js
{
path: 'settings/hotspots/delete/:hotspotId/:actionId',
hook: (application, {hotspotId, actionId}) => {
console.log('do something with', application)
console.log('or param', hotspotId, actionId)
}
}
```
## Route Options
For specific routes, you can specify an object that contains `options` to influence the Router's behavior for those routes. These are:
* [preventStorage](#preventstorage)
* [clearHistory](#clearhistory)
* [reuseInstance](#reuseinstance)
* [beforeNavigate](#beforenavigate)
For example:
```js
{
path: 'settings/hotspots/delete/:hotspotId/:actionId',
options: {
preventStorage: true,
clearHistory: true,
reuseInstance: false
}
}
```
### preventStorage
Indicates whether or not to prevent a route from storage in history. Possible values: `true` or `false` (default).
### clearHistory
Indicates whether or not to reset the history of a route when that route is visited. Possible values: `true` or `false` (default).
### reuseInstance
Indicates whether or not to reuse the current Page instance. Possible values: `true` (default) or `false`.
When the new hash that you navigate to, shares the same route and the previous:
`settings/hotspot/12` && `settings/hotspot/22`
share: `settings/hotspot/:id`,
the Router reuses the current Page instance by default.
If you want to prevent this, you set `reuseInstance: false`. This [setting](settings.md#reuseinstance) is also globally available.
### beforeNavigate
This is a local hook that you can specify for a specific route, and is invoked right before the Router navigates to that route.
It follows the same rules as the [global ](#beforeeachroute) hook `beforeEachRoute`. For example:
```js
{
path: 'player/:playlistId${/[0-9]{3,8}/i}',
component: Player,
beforeNavigate:(from)=>{
return new Promise((resolve)=>{
if(from === "home/browse/adventure"){
resolve(true)
}
})
}
}
```
## Special Routes
There are three *special* routes that can be configured in the `routes` Array, and are *not* added to the history stack. These special routes are:
* [BootPage](#bootpage)
* [NotFoundPage](#notfoundpage)
* [ErrorPage](#errorpage)
### BootPage
If you want to display a **Splash** or **Loading** screen while the Router is booting (and *before* the actual routing process kicks in), you can specify a Lightning Component in the `bootComponent` key of the configuration object.
The component is not only displayed when you open the root of your App, but also when you open a [deeplinked](deeplinking.md) location in the App.
```js
{
path: '$',
component: BootPage
}
```
> Since the `BootPage` might show an animation that takes some time to finish, the Router plugin does not hide
the `BootPage` automatically. Instead, you have to *explicitly* call `Router.resume()` in your `BootPage` to give control back to the Router plugin.
### NotFoundPage
The `*` path indicates which Page component must be displayed when an *unknown* route path is hit (i.e., URL not found):
```js
{
path: '*',
component: NotFoundPage
}
```
### ErrorPage
The `!` path indicates which Page component must be displayed as a *global error page*.
The Router displays this route when the [data provider](dataproviding.md) of a page returns an error. For example:
```js
{
path: '!',
component: ErrorPage
}
```
#### NEXT:
[Navigation](navigation.md)