OLD | NEW |
1 ## Router for Web Components | 1 ## Router for Web Components |
2 > Works with [Polymer](http://www.polymer-project.org/), [X-Tag](http://www.x-ta
gs.org/), and natively with the [platform](https://github.com/Polymer/platform)
polyfill. | 2 > Works with [Polymer](http://www.polymer-project.org/), [X-Tag](http://www.x-ta
gs.org/), and natively. |
| 3 > |
| 4 > [erikringsmuth.github.io/app-router](https://erikringsmuth.github.io/app-route
r/) |
3 | 5 |
4 > [erikringsmuth.github.io/app-router](http://erikringsmuth.github.io/app-router
) | 6 Manage page state. Lazy-load content. Data-bind path variables and query paramet
ers. Use multiple layouts. Navigate with `hashchange` and HTML5 `pushState`. Ani
mate transitions using `core-animated-pages`. |
5 | |
6 Lazy-loads content. Binds path variables and query parameters to the page elemen
t's attributes. Supports multiple layouts. Works with `hashchange` and HTML5 `pu
shState`. One set of routes will match regular paths `/`, hash paths `#/`, and h
ashbang paths `#!/`. | |
7 | 7 |
8 [Download](https://github.com/erikringsmuth/app-router/archive/master.zip) or ru
n `bower install app-router --save`. | 8 [Download](https://github.com/erikringsmuth/app-router/archive/master.zip) or ru
n `bower install app-router --save`. |
9 | 9 |
10 ## Configuration | 10 ## Configuration |
11 | 11 |
| 12 Define how URLs map to pages. |
| 13 |
12 ```html | 14 ```html |
13 <!doctype html> | 15 <!doctype html> |
14 <html> | 16 <html> |
15 <head> | 17 <head> |
16 <title>App Router</title> | 18 <title>App Router</title> |
17 <link rel="import" href="/bower_components/app-router/app-router.html"> | 19 <link rel="import" href="/bower_components/app-router/app-router.html"> |
18 </head> | 20 </head> |
19 <body> | 21 <body> |
20 <app-router> | 22 <app-router> |
21 <!-- matches an exact path --> | 23 <!-- matches an exact path --> |
22 <app-route path="/home" import="/pages/home-page.html"></app-route> | 24 <app-route path="/home" import="/pages/home-page.html"></app-route> |
23 | 25 |
24 <!-- matches using a wildcard --> | 26 <!-- matches using a wildcard --> |
25 <app-route path="/customer/*" import="/pages/customer-page.html"></app-rou
te> | 27 <app-route path="/customer/*" import="/pages/customer-page.html"></app-rou
te> |
26 | 28 |
27 <!-- matches using a path variable --> | 29 <!-- matches using a path variable --> |
28 <app-route path="/order/:id" import="/pages/order-page.html"></app-route> | 30 <app-route path="/order/:id" import="/pages/order-page.html"></app-route> |
29 | 31 |
30 <!-- matches a pattern like '/word/number' --> | 32 <!-- matches a pattern like '/word/number' --> |
31 <app-route path="/^\/\w+\/\d+$/i" regex import="/pages/regex-page.html"></
app-route> | 33 <app-route path="/^\/\w+\/\d+$/i" regex import="/pages/regex-page.html"></
app-route> |
32 | 34 |
33 <!-- matches everything else --> | 35 <!-- matches everything else --> |
34 <app-route path="*" import="/pages/not-found-page.html"></app-route> | 36 <app-route path="*" import="/pages/not-found-page.html"></app-route> |
35 </app-router> | 37 </app-router> |
36 </body> | 38 </body> |
37 </html> | 39 </html> |
38 ``` | 40 ``` |
39 | 41 |
40 Changing the URL will find the first `app-route` that matches, load the element
or template, and replace the current view. | 42 ## Navigation |
| 43 |
| 44 Click links or call `router.go()`. |
| 45 |
| 46 ```html |
| 47 <!-- hashchange --> |
| 48 <a href="/#/home">Home</a> |
| 49 |
| 50 <!-- pushState() --> |
| 51 <a is="pushstate-anchor" href="/home">Home</a> |
| 52 |
| 53 <!-- router.go(path, options) --> |
| 54 <script> |
| 55 document.querySelector('app-router').go('/home'); |
| 56 </script> |
| 57 ``` |
| 58 |
| 59 The router listens to `popstate` and `hashchange` events. Changing the URL will
find the first `app-route` that matches, load the element or template, and repla
ce the current view. |
| 60 |
| 61 #### hashchange |
| 62 Clicking `<a href="/#/home">Home</a>` will fire a `hashchange` event and tell th
e router to load the first route that matches `/home`. You don't need to handle
the event in your Javascript. Hash paths `/#/home` match routes without the hash
`<app-route path="/home">`. |
| 63 |
| 64 #### pushState |
| 65 You can use the [pushstate-anchor](https://github.com/erikringsmuth/pushstate-an
chor) or [html5-history-anchor](https://github.com/erikringsmuth/html5-history-a
nchor) to extend `<a>` tags with the HTML5 history API. |
| 66 |
| 67 ```html |
| 68 <a is="pushstate-anchor" href="/home">Home</a> |
| 69 ``` |
| 70 |
| 71 This will call `pushState()` and dispatch a `popstate` event. |
| 72 |
| 73 #### go(path, options) |
| 74 You can call the router from Javascript to navigate imperatively. |
| 75 |
| 76 ```js |
| 77 document.querySelector('app-router').go('/home'); |
| 78 // or |
| 79 document.querySelector('app-router').go('/home', {replace: true}); |
| 80 ``` |
| 81 |
| 82 If you use `go(path, options)` you should also set the mode to `hash` or `pushst
ate` on the router. |
| 83 |
| 84 ```html |
| 85 <app-router mode="auto|pushstate|hash"> |
| 86 <!-- app-routes --> |
| 87 </app-router> |
| 88 ``` |
41 | 89 |
42 ## Data Binding | 90 ## Data Binding |
43 Path variables and query parameters automatically attach to the element's attrib
utes. | 91 Path variables and query parameters automatically attach to the element's attrib
utes. |
44 | 92 |
45 ``` html | 93 ``` html |
46 <!-- url --> | 94 <!-- url --> |
47 http://www.example.com/order/123?sort=ascending | 95 <a is="pushstate-anchor" href="/order/123?sort=ascending">Order 123</a> |
48 | 96 |
49 <!-- route --> | 97 <!-- route --> |
50 <app-route path="/order/:id" import="/pages/order-page.html"></app-route> | 98 <app-route path="/order/:orderId" import="/pages/order-page.html"></app-route> |
51 | 99 |
52 <!-- will bind 123 to the page's `id` attribute and "ascending" to the `sort` at
tribute --> | 100 <!-- will bind 123 to the page's `orderId` attribute and "ascending" to the `sor
t` attribute --> |
53 <order-page id="123" sort="ascending"></order-page> | 101 <order-page orderId="123" sort="ascending"></order-page> |
54 ``` | 102 ``` |
55 | 103 |
56 See it in action [here](http://erikringsmuth.github.io/app-router/#/databinding/
1337?queryParam1=Routing%20with%20Web%20Components!). | 104 If you're using Polymer, you can also bind path variables and query parameters t
o templates. |
57 | |
58 ## Multiple Layouts | |
59 Each page chooses which layout to use. This allows multiple layouts in the same
app. Use `<content>` tag insertion points to insert the page into the layout. Th
is is similar to nested routes but completely decouples the page layout from the
router. | |
60 | |
61 This is a simple example showing a page and it's layout. | |
62 | |
63 #### home-page.html | |
64 | |
65 ```html | 105 ```html |
66 <link rel="import" href="/layouts/simple-layout.html"> | 106 <app-route path="/order/:orderId"> |
67 <polymer-element name="home-page" noscript> | |
68 <template> | 107 <template> |
69 <simple-layout> | 108 <p>Your order number is {{orderId}}</p> |
70 <div class="title">Home</div> | |
71 <p>The home page!</p> | |
72 </simple-layout> | |
73 </template> | 109 </template> |
74 </polymer-element> | 110 </app-route> |
75 ``` | 111 ``` |
76 | 112 |
77 #### simple-layout.html | 113 See it in action [here](https://erikringsmuth.github.io/app-router/#/databinding
/1337?queryParam1=Routing%20with%20Web%20Components!). |
78 | |
79 ```html | |
80 <polymer-element name="simple-layout" noscript> | |
81 <template> | |
82 <core-toolbar> | |
83 <content select=".title"><!-- content with class 'title' --></content> | |
84 </core-toolbar> | |
85 <content><!-- all other content --></content> | |
86 </template> | |
87 </polymer-element> | |
88 ``` | |
89 | 114 |
90 ## <app-route> options | 115 ## <app-route> options |
91 | 116 |
92 #### import a custom element | 117 #### import a custom element |
93 Lazy-load a custom element. | 118 Lazy-load a custom element. |
94 | 119 |
95 ```html | 120 ```html |
96 <app-route path="/customer/:customerId" import="/pages/customer-page.html"></app
-route> | 121 <app-route path="/customer/:customerId" import="/pages/customer-page.html" [elem
ent="customer-page"]></app-route> |
97 ``` | 122 ``` |
98 | 123 |
99 When you navigate to `/customer/123` the router will load `/pages/customer-page.
html`, replace the active view with a new `customer-page` element, and bind any
attributes `element.setAttribute('customerId', 123)`. | 124 You only need to set the `element` attribute if the element's name is different
than the file name. |
100 | |
101 You can manually set the element's name with the `element` attribute if it's dif
ferent from the file name. This is useful when bundling (vulcanizing) custom ele
ments. | |
102 | |
103 ```html | |
104 <app-route path="/customer/:customerId" import="/pages/page-bundle.html" element
="customer-page"></app-route> | |
105 ``` | |
106 | 125 |
107 #### pre-loaded custom element | 126 #### pre-loaded custom element |
108 You can route to a pre-loaded custom element. In this case, load the element nor
mally in the `<head>` and include the `element="element-name"` attribute on the
route. This is how you'd bundle and pre-load custom elements. | 127 Include the `element="element-name"` attribute on the route to use a pre-loaded
custom element. This is how you use bundled (vulcanized) custom elements. |
109 | 128 |
110 ```html | 129 ```html |
111 <head> | 130 <head> |
112 <link rel="import" href="/pages/page-bundle.html"> | 131 <link rel="import" href="/pages/page-bundle.html"> |
113 </head> | 132 </head> |
114 <app-router> | 133 <app-router> |
115 <app-route path="/customer/:customerId" element="customer-page"></app-route> | 134 <app-route path="/customer/:customerId" element="customer-page"></app-route> |
116 </app-router> | 135 </app-router> |
117 ``` | 136 ``` |
118 | 137 |
119 #### import template | 138 #### import template |
120 You can use a `<template>` instead of a custom element. This doesn't have data b
inding and is lighter-weight than a custom element. Just include the `template`
attribute. | 139 You can import a `<template>` instead of a custom element. Just include the `tem
plate` attribute. |
121 | 140 |
122 ```html | 141 ```html |
123 <app-route path="/example" import="/pages/template-page.html" template></app-rou
te> | 142 <app-route path="/example" import="/pages/template-page.html" template></app-rou
te> |
124 ``` | 143 ``` |
125 | 144 |
126 #### inline template | 145 #### inline template |
127 Finally, you can in-line a `<template>` like this. | 146 Finally, you can in-line a `<template>` like this. |
128 | 147 |
129 ```html | 148 ```html |
130 <app-route path="/example" template> | 149 <app-route path="/example"> |
131 <template> | 150 <template> |
132 <p>Inline template FTW!</p> | 151 <p>Inline template FTW!</p> |
133 </template> | 152 </template> |
134 </app-route> | 153 </app-route> |
135 ``` | 154 ``` |
136 | 155 |
137 #### regular expressions | 156 #### regular expressions |
138 Include the `regex` attribute to match on a regular expression. The format is th
e same as a JavaScript regular expression. | 157 Include the `regex` attribute to match on a regular expression. The format is th
e same as a JavaScript regular expression. |
| 158 |
139 ```html | 159 ```html |
140 <!-- matches a pattern like '/word/number' --> | 160 <!-- matches a pattern like '/word/number' --> |
141 <app-route path="/^\/\w+\/\d+$/i" regex import="/pages/regex-page.html"></app-ro
ute> | 161 <app-route path="/^\/\w+\/\d+$/i" regex import="/pages/regex-page.html"></app-ro
ute> |
142 ``` | 162 ``` |
143 Note: The regular expression must start with a `/` and end with a `/` optionally
followed by `i`. Options global `g`, multiline `m`, and sticky `y` aren't valid
when matching paths. | 163 |
| 164 #### redirect |
| 165 A route can redirect to another path. |
| 166 |
| 167 ```html |
| 168 <app-router mode="pushstate"> |
| 169 <app-route path="/home" import="/pages/home-page.html"></app-route> |
| 170 <app-route path="*" redirect="/home"></app-route> |
| 171 </app-router> |
| 172 ``` |
| 173 |
| 174 When you use `redirect` you should also set `mode="hash|pushstate"` on the `app-
router`. |
144 | 175 |
145 ## <app-router> options | 176 ## <app-router> options |
146 | 177 |
147 #### Trailing Slashes | 178 #### mode |
| 179 One set of routes will match regular paths `/` and hash paths `#/`. You can forc
e a specific mode with `mode="auto|hash|pushstate"`. |
| 180 |
| 181 ```html |
| 182 <app-router mode="pushstate"> |
| 183 <!-- always ignore the hash and match on the path --> |
| 184 </app-router> |
| 185 ``` |
| 186 |
| 187 When left in `auto`, redirects and `go(path, options)` will use hash paths. |
| 188 |
| 189 #### trailing slashes |
148 By default `/home` and `/home/` are treated as separate routes. You can configur
e the router to ignore trailing slashes with `trailingSlash="ignore"`. | 190 By default `/home` and `/home/` are treated as separate routes. You can configur
e the router to ignore trailing slashes with `trailingSlash="ignore"`. |
149 ```html | 191 ```html |
150 <app-router trailingSlash="ignore"> | 192 <app-router trailingSlash="ignore"> |
151 <!-- matches '/home' and '/home/' --> | 193 <!-- matches '/home' and '/home/' --> |
152 <app-route path="/home" import="/pages/home-page.html"></app-route> | 194 <app-route path="/home" import="/pages/home-page.html"></app-route> |
153 </app-router> | 195 </app-router> |
154 ``` | 196 ``` |
155 | 197 |
156 ## Navigation | |
157 There are three ways change the active route. `hashchange`, `pushState()`, and a
full page load. | |
158 | |
159 #### hashchange | |
160 If you're using `hashchange` you don't need to do anything. Clicking a link `<a
href="/#/new/page">New Page</a>` will fire a `hashchange` event and tell the rou
ter to load the new route. You don't need to handle the event in your code. | |
161 | |
162 #### pushState | |
163 If you're using HTML5 `pushState` you need one extra step. The `pushState()` met
hod was not meant to change the page, it was only meant to push state into histo
ry. This is an "undo" feature for single page applications. To use `pushState()`
to navigate to another route you need to call it like this. | |
164 | |
165 ```js | |
166 history.pushState(stateObj, title, '/new/page'); // push a new URL into the hist
ory stack | |
167 history.go(0); // go to the current state in the history stack, this fires a pop
state event | |
168 ``` | |
169 | |
170 #### Full page load | |
171 Clicking a link `<a href="/new/page">New Page</a>` without a hash path will do a
full page load. You need to make sure your server will return `index.html` when
looking up the resource at `/new/page`. The simplest set up is to always return
`index.html` and let the `app-router` handle the routing including a not found
page. | |
172 | |
173 ## Demo Site & Example Setup | 198 ## Demo Site & Example Setup |
174 Check out the `app-router` in action at [erikringsmuth.github.io/app-router](htt
p://erikringsmuth.github.io/app-router). | 199 Check out the `app-router` in action at [erikringsmuth.github.io/app-router](htt
ps://erikringsmuth.github.io/app-router/). |
175 | 200 |
176 You can download an example setup here https://github.com/erikringsmuth/app-rout
er-examples to get running locally. | 201 You can download an example setup here https://github.com/erikringsmuth/app-rout
er-examples to get running locally. |
177 | 202 |
| 203 Examples showing `app-router` and `flatiron-director` versus no router https://g
ithub.com/erikringsmuth/polymer-router-demos. |
| 204 |
| 205 ## Breaking Changes |
| 206 Check the [change log](https://github.com/erikringsmuth/app-router/blob/master/c
hangelog.md) for breaking changes in major versions. |
| 207 |
178 ## Build, Test, and Debug [](https://travis-ci.org/erikringsmuth/app-router) | 208 ## Build, Test, and Debug [](https://travis-ci.org/erikringsmuth/app-router) |
179 Source files are under the `src` folder. The build process writes to the root di
rectory. The easiest way to debug is to include the source script rather than th
e minified HTML import. | 209 Source files are under the `src` folder. The build process writes to the root di
rectory. The easiest way to debug is to include the source script rather than th
e minified HTML import. |
180 ```html | 210 ```html |
181 <script src="/bower_components/app-router/src/app-router.js"></script> | 211 <script src="/bower_components/app-router/src/app-router.js"></script> |
182 ``` | 212 ``` |
183 | 213 |
184 To build: | 214 To build: |
185 - Run `bower install` and `npm install` to install dev dependencies | 215 - Run `bower install` and `npm install` to install dev dependencies |
186 - Lint, build, and minify code changes with `gulp` (watch with `gulp watch`) | 216 - Lint, test, build, and minify code with `gulp` |
187 - Start a static content server to run tests (node `http-server` or `python -m S
impleHTTPServer`) | 217 - Manually run functional tests in the browser by starting a static content serv
er (node `http-server` or `python -m SimpleHTTPServer`) and open [http://localho
st:8080/tests/functional-tests/](http://localhost:8080/tests/functional-tests/) |
188 - Run unit tests in the browser (PhantomJS doesn't support Web Components) [http
://localhost:8080/tests/SpecRunner.html](http://localhost:8080/tests/SpecRunner.
html) | |
189 - Manually run functional tests in the browser [http://localhost:8080/tests/func
tional-test-site/](http://localhost:8080/tests/functional-test-site/) | |
OLD | NEW |