|
| 1 | +# Client-Side Routing |
| 2 | + |
| 3 | +Picard.js contains a client-side router that works by patching the [HTML5 history API](https://developer.mozilla.org/en-US/docs/Web/API/History_API). |
| 4 | + |
| 5 | +## Router Events |
| 6 | + |
| 7 | +Besides the standard `popstate` some new events have been added. The `history` element now dispatches the following events at `window`: |
| 8 | + |
| 9 | +| Name | Events Arguments | Description | |
| 10 | +| ----------------- | ----------------------------------------- | --------------------------------------------------------------- | |
| 11 | +| `popstate` | `PopStateEvent` with the provided `state` | More information [available online](https://developer.mozilla.org/en-US/docs/Web/API/Window/popstate_event) |
| 12 | +| `pushstate` | `Event` with the sender | Dispatched after `pushState` has been called | |
| 13 | +| `replacestate` | `Event` with the sender | Dispatched after `replaceState` has been called | |
| 14 | + |
| 15 | +## Presenting Router Content |
| 16 | + |
| 17 | +Components may be registered for specific routes using a conventional component name prefixed with `page:`. For instance, a component that should be displayed at `/` should be registered with the name `page:/`. |
| 18 | + |
| 19 | +The `rel="router"` attribute changes a `pi-slot` web component to listen to the currently active route. It will then sync the `name` attribute of the `pi-slot` instance to `page:[current-page]`, where `[current-page]` is the path using the history API. |
| 20 | + |
| 21 | +The following piece of HTML is everything required to display those pages. |
| 22 | + |
| 23 | +```html |
| 24 | +<pi-slot rel="router"></pi-slot> |
| 25 | +``` |
| 26 | + |
| 27 | +A 404 (page not found) content can be shown by introducing a fallback, like for any other `pi-slot`: |
| 28 | + |
| 29 | +```html |
| 30 | +<pi-slot rel="router" fallback-template-id="not-found-page"></pi-slot> |
| 31 | + |
| 32 | +<template id="not-found-page"> |
| 33 | + <div class="flex flex-1"> |
| 34 | + <h1>Page Not Found</h1> |
| 35 | + <p>The provided page has not been found.</p> |
| 36 | + </div> |
| 37 | +</template> |
| 38 | +``` |
| 39 | + |
| 40 | +There can be multiple `pi-slot` instances on one page. All would be synced to the current path. |
| 41 | + |
| 42 | +## Changing the Route |
| 43 | + |
| 44 | +There are two primary ways to interact with the router: |
| 45 | + |
| 46 | +1. By interacting with the HTML5 `history` object, e.g., `history.pushState({}, '', '/')`. |
| 47 | +2. By placing standard `a` elements on the page that have no target (or go to `_self`) and feature a *local* `href` attribute. |
| 48 | + |
| 49 | +In the second case clicking such anchor tags will be intercepted and the usual (full page) navigation will be aborted. Instead, the HTML5 history API is called and the scroll is reset (i.e., `window.scrollTo(0, 0)` is called). |
| 50 | + |
| 51 | +## Route Parameters |
| 52 | + |
| 53 | +The register page path can also consider route parameters. As an example, if you want to receive the value of a parameter `id`, which should be the ID of a product, then a route definition such as `/product/:id` would be suitable: |
| 54 | + |
| 55 | +``` |
| 56 | +page:/product/:id |
| 57 | +``` |
| 58 | + |
| 59 | +The router also recognizes optional segments. For instance, if a products page can be used with and without a category, you might define a route such: |
| 60 | + |
| 61 | +``` |
| 62 | +page:/products{/:category}? |
| 63 | +``` |
| 64 | + |
| 65 | +This way, you'd receive the `category` parameter only if it was set. Both paths, `/products` and `/products/foo` would be handled by Picard.js. |
| 66 | + |
| 67 | +| Syntax | Type | Description | Example | |
| 68 | +| ------- | ---------- | --------------------------------------------------- | ------------- | |
| 69 | +| `:id` | `string` | A required parameter within a route. | `/foo/:id` | |
| 70 | +| `*s` | `string[]` | A wildcard parameter taking the remaining segments. | `/foo/*splat` | |
| 71 | +| `{opt}` | `string?` | An optional segment is enclosed in braces. | `/foo{/bar}` | |
0 commit comments