forked from agsdot/mithril
-
Notifications
You must be signed in to change notification settings - Fork 0
/
mithril.route.html
387 lines (374 loc) · 21.2 KB
/
mithril.route.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
<!doctype html>
<html>
<head>
<title>m.route - Mithril</title>
<meta name="description" value="Mithril.js - a Javascript Framework for Building Brilliant Applications" />
<link href="lib/prism/prism.css" rel="stylesheet" />
<link href="style.css" rel="stylesheet" />
</head>
<body>
<header>
<nav class="container">
<a href="index.html" class="logo"><span>○</span> Mithril</a>
<a href="getting-started.html">Guide</a>
<a href="mithril.html">API</a>
<a href="community.html">Community</a>
<a href="http://lhorie.github.io/mithril-blog">Learn</a>
<a href="mithril.min.zip">Download</a>
<a href="http://github.com/lhorie/mithril.js" target="_blank">Github</a>
</nav>
</header>
<main>
<section class="content">
<div class="container">
<div class="row">
<div class="col(3,3,12)">
<h2 id="api">API (v0.2.0)</h2>
<h3 id="core">Core</h3>
<ul>
<li><a href="mithril.html" title="A utility to create virtual elements">m</a></li>
<li><a href="mithril.component.html" title="Parameterizes a component">m.component</a></li>
<li><a href="mithril.mount.html" title="Renders a component">m.mount</a></li>
<li><a href="mithril.prop.html" title="A getter-setter utility">m.prop</a></li>
<li><a href="mithril.withAttr.html" title="A event handler factory utility">m.withAttr</a></li>
</ul>
<h3 id="routing">Routing</h3>
<ul>
<li><a href="mithril.route.html" title="A routing utility">m.route</a>
<ul>
<li><a href="mithril.route.html#defining-routes" title="Defines what routes exist">m.route(rootElement, defaultRoute, routes)</a></li>
<li><a href="mithril.route.html#redirecting" title="Redirects to a route">m.route(path, params, replaceHistory)</a></li>
<li><a href="mithril.route.html#reading-current-route" title="Read the current route">m.route()</a></li>
<li><a href="mithril.route.html#mode-abstraction" title="Routing mode abstraction">m.route(element)</a></li>
<li><a href="mithril.route.html#mode" title="Whether routing uses location hash, querystring or pathname">m.route.mode</a></li>
<li><a href="mithril.route.html#param" title="Read an argument from a parameterized route">m.route.param</a></li>
<li><a href="mithril.route.html#buildQueryString" title="Serialize data into querystring format">m.route.buildQueryString</a></li>
<li><a href="mithril.route.html#parseQueryString" title="Read an argument from a parameterized route">m.route.parseQueryString</a></li>
</ul>
</li>
</ul>
<h3 id="data">Data</h3>
<ul>
<li><a href="mithril.request.html" title="A high-level AJAX utility">m.request</a></li>
<li><a href="mithril.deferred.html" title="A Promise factory">m.deferred</a></li>
<li><a href="mithril.sync.html" title="A Promise aggregator">m.sync</a></li>
</ul>
<h3 id="html">HTML</h3>
<ul>
<li><a href="mithril.trust.html" title="A method to unescape HTML">m.trust</a></li>
</ul>
<h3 id="rendering">Rendering</h3>
<ul>
<li><a href="mithril.render.html" title="The lowest level rendering method">m.render</a></li>
<li><a href="mithril.redraw.html" title="A high-level explicit rendering method">m.redraw</a>
<ul>
<li><a href="mithril.redraw.html#strategy" title="A flag that drives the rendering strategy for the next redraw">m.redraw.strategy(strategy)</a></li>
</ul>
</li>
<li><a href="mithril.computation.html" title="Utilities to integrate asynchronous contexts to the rendering system">m.startComputation / m.endComputation</a></li>
</ul>
<h3 id="data">Testing</h3>
<ul>
<li><a href="mithril.deps.html" title="The dependency injector">m.deps</a></li>
</ul>
<h2 id="archive">History</h2>
<ul>
<li><a href="roadmap.html">Roadmap</a></li>
<li><a href="change-log.html">Change log</a></li>
</ul>
</div>
<div class="col(9,9,12)">
<h2 id="m-route">m.route</h2>
<hr>
<ul>
<li><a href="#defining-routes">Defining routes</a></li>
<li><a href="#variadic-routes">Variadic routes</a></li>
<li><a href="#routes-with-querystrings">Routes with querystrings</a></li>
<li><a href="#running-clean-up-code-on-route-change">Running clean up code on route change</a></li>
<li><a href="#redirecting">Redirecting</a></li>
<li><a href="#reading-the-currently-active-route">Reading the currently active route</a></li>
<li><a href="#mode-abstraction">Mode abstraction</a></li>
</ul>
<hr>
<p>Routing is a system that allows creating Single-Page-Applications (SPA), i.e. applications that can go from a page to another without causing a full browser refresh.</p>
<p>It enables seamless navigability while preserving the ability to bookmark each page individually, and the ability to navigate the application via the browser's history mechanism.</p>
<p>This method overloads four different units of functionality:</p>
<ul>
<li><p><code>m.route(rootElement, defaultRoute, routes)</code> - defines the available URLs in an application, and their respective components</p>
</li>
<li><p><code>m.route(path)</code> - redirects to another route</p>
</li>
<li><p><code>m.route()</code> - returns the currently active route</p>
</li>
<li><p><code>m.route(element)</code> - an extension to link elements that unobtrusively abstracts away the routing mode</p>
</li>
</ul>
<p>Routing is single-page-application (SPA) friendly, and can be implemented using either <code>location.hash</code>, HTML5 URL rewriting or <code>location.querystring</code>. See <a href="#mode"><code>m.route.mode</code></a> for the caveats of each implementation.</p>
<hr>
<h3 id="defining-routes">Defining routes</h3>
<h4 id="usage">Usage</h4>
<p>To define a list of routes, you need to specify a host DOM element, a default route and a key-value map of possible routes and respective <a href="mithril.component.html">components</a> to be rendered. You don't need to call <a href="mithril.mount.html"><code>m.mount</code></a> to initialize your components if you define a list of routes - <code>m.route</code> calls it for you.</p>
<p>The example below defines three routes, to be rendered in <code><body></code>. <code>Home</code>, <code>Login</code> and <code>Dashboard</code> are components. We'll see how to define a component in a bit.</p>
<pre><code class="lang-javascript">m.route(document.body, "/", {
"/": Home,
"/login": Login,
"/dashboard": Dashboard,
});
</code></pre>
<p>Routes can take arguments, by prefixing words with a colon <code>:</code></p>
<p>The example below shows a route that takes an <code>userID</code> parameter</p>
<pre><code class="lang-javascript">//a sample component
var Dashboard = {
controller: function() {
return {id: m.route.param("userID")}
},
view: function(controller) {
return m("div", controller.id);
}
}
//setup routes to start w/ the `#` symbol
m.route.mode = "hash";
//define a route
m.route(document.body, "/dashboard/johndoe", {
"/dashboard/:userID": Dashboard
});
</code></pre>
<p>This redirects to the URL <code>http://server/#/dashboard/johndoe</code> and yields:</p>
<pre><code class="lang-markup"><body><div>johndoe</div></body>
</code></pre>
<p>Above, <code>dashboard</code> is a component. It contains a <code>controller</code> and a <code>view</code> properties. When the URL matches a route, the respective component's controller is instantiated and passed as a parameter to the view.</p>
<p>In this case, since there's only one route, the app redirects to the default route <code>"/dashboard/johndoe"</code>.</p>
<p>The string <code>johndoe</code> is bound to the <code>:userID</code> parameter, which can be retrieved programmatically in the controller via <code>m.route.param("userID")</code>.</p>
<p>The <code>m.route.mode</code> defines which part of the URL to use for routing.</p>
<hr>
<h4 id="variadic-routes">Variadic routes</h4>
<p>We can append an ellipsis (<code>...</code>) to the name of a route argument to allow it to match URL snippets that contain slashes:</p>
<pre><code class="lang-javascript">m.route(document.body, "/files/pictures/pic1.jpg", {
"/files/:file...": gallery
});
m.route.param("file") === "pictures/pic1.jpg"
</code></pre>
<pre><code class="lang-javascript">m.route(document.body, "/blog/2014/01/20/articles", {
"/blog/:date.../articles": articleList
});
m.route.param("date") === "2014/01/20"
</code></pre>
<p>Note that Mithril checks for route matches in the order the routes are defined, so you should put variadic routes at the bottom of the list to prevent them from matching other more specific routes.</p>
<pre><code>m.route(document.body, "/blog/archive/2014", {
"/blog/:date...": Component1, //for the default path in the line above, this route matches first!
"/blog/archive/:year": Component2
});
m.route.param("date") === "archive/2014"
//the routes should be flipped around to get `m.route.param("year") == "2014"`
</code></pre><hr>
<h4 id="routes-with-querystrings">Routes with querystrings</h4>
<p>In addition to route parameters, it's possible to pass arbitrary data to <code>m.route.param</code> using the querystring</p>
<pre><code class="lang-javascript">m.route("/grid?sortby=date&dir=desc")
var sortBy = m.route.param("sortby") // "date"
var dir = m.route.param("dir") // "desc"
</code></pre>
<hr>
<h4 id="running-clean-up-code-on-route-change">Running clean up code on route change</h4>
<p>If a component's controller implements an instance method called <code>onunload</code>, this method will be called when a route changes.</p>
<pre><code class="lang-javascript">var Home = {
controller: function() {
return {
onunload: function() {
console.log("unloading home component");
}
};
},
view: function() {
return m("div", "Home")
}
};
var Dashboard = {
controller: function() {},
view: function() {}
};
//go to the default route (home)
m.route(document.body, "/", {
"/": Home,
"/dashboard": Dashboard,
});
//re-route to dashboard
m.route("/dashboard"); // logs "unloading home"
</code></pre>
<p>This mechanism is useful to clear timers and unsubscribe event handlers. If you have a hierarchy of components, you can recursively call <code>onunload</code> on all the components in the tree or use a <a href="http://microjs.com/#pubsub">pubsub</a> library to unload specific components on demand.</p>
<hr>
<h4 id="signature">Signature</h4>
<p><a href="how-to-read-signatures.html">How to read signatures</a></p>
<pre><code class="lang-clike">void route(DOMElement rootElement, String defaultRoute, Object<Component> routes) { String mode, String param(String key), String buildQueryString(Object data), Object parseQueryString(String data) }
where:
Component :: Object { void controller(), void view(Object controllerInstance) }
</code></pre>
<ul>
<li><p><strong>DOMElement root</strong></p>
<p>A DOM element which will contain the view's template.</p>
</li>
<li><p><strong>String defaultRoute</strong></p>
<p>The route to redirect to if the current URL does not match any of the defined routes</p>
</li>
<li><p><strong>Object<Component> routes</strong></p>
<p>A key-value map of possible routes and their respective components. Keys are expected to be absolute pathnames, but can include dynamic parameters. Dynamic parameters are words preceded by a colon <code>:</code></p>
<p><code>{'/path/to/page/': pageComponent}</code> - a route with a basic pathname</p>
<p><code>{'/path/to/page/:id': pageComponent}</code> - a route with a pathname that contains a dynamic parameter called <code>id</code>. This route would be selected if the URL was <code>/path/to/page/1</code>, <code>/path/to/page/test</code>, etc</p>
<p><code>{'/user/:userId/book/:bookId': userBookComponent}</code> - a route with a pathname that contains two parameters</p>
<p>Dynamic parameters are wild cards that allow selecting a component based on a URL pattern. The values that replace the dynamic parameters in a URL are available via <code>m.route.param()</code></p>
<p>Note that the URL component used to resolve routes is dependent on <code>m.route.mode</code>. By default, the querystring is considered the URL component to test against the routes collection</p>
<p>If the current page URL matches a route, its respective component is activated. See <a href="mithril.component.html"><code>m.component</code></a> for information on components.</p>
</li>
<li><p><a name="mode"></a></p>
<h4 id="m-route-mode">m.route.mode</h4>
<p><strong>String mode</strong></p>
<p>The <code>m.route.mode</code> property defines which URL portion is used to implement the routing mechanism. Its value can be set to either "search", "hash" or "pathname". Default value is "search". Note that if you're changing this configuration value, you should change it <strong>before</strong> calling <code>m.route</code>.</p>
<ul>
<li><p><code>search</code> mode uses the querystring (i.e. <code>?</code>). This allows named anchors (i.e. <code><a href="#top">Back to top</a></code>, <code><a name="top"></a></code>) to work on the page, but routing changes causes page refreshes in IE8, due to its lack of support for <code>history.pushState</code>.</p>
<p>Example URL: <code>http://server/?/path/to/page</code></p>
</li>
<li><p><code>hash</code> mode uses the hash (i.e. <code>#</code>). It's the only mode in which routing changes do not cause page refreshes in any browser. However, this mode does not support named anchors.</p>
<p>Example URL: <code>http://server/#/path/to/page</code></p>
</li>
<li><p><code>pathname</code> mode allows routing URLs that contains no special characters, however this mode requires server-side setup in order to support bookmarking and page refreshes. It always causes page refreshes in IE8.</p>
<p>Example URL: <code>http://server/path/to/page</code></p>
<p>The simplest server-side setup possible to support pathname mode is to serve the same content regardless of what URL is requested. In Apache, this URL rewriting can be achieved using ModRewrite.</p>
<p>Note that in order to use the <code>pathname</code> mode, the application must be run from the root URL.</p>
</li>
</ul>
</li>
<li><p><a name="param"></a></p>
<h4 id="m-route-param">m.route.param</h4>
<p><strong>String param(String key)</strong></p>
<p>Route parameters are dynamic values that can be extracted from the URL based on the signature of the currently active route.</p>
<p>A route without parameters looks like this:</p>
<p><code>"/path/to/page/"</code></p>
<p>A route with parameters might look like this:</p>
<p><code>"/path/to/page/:id"</code> - here, <code>id</code> is the name of the route parameter</p>
<p>If the currently active route is <code>/dashboard/:userID</code> and the current URL is <code>/dashboard/johndoe</code>, then calling <code>m.route.param("userID")</code> returns <code>"johndoe"</code></p>
<p>Querystring parameters in a route are also available in this collection automatically.</p>
<p><code>"/grid?sortby=date"</code> - here, <code>m.route.param("sortby")</code> returns <code>"date"</code></p>
<ul>
<li><p><strong>String key</strong></p>
<p>The name of a route parameter</p>
</li>
<li><p><strong>returns String value</strong></p>
<p>The value that maps to the parameter specified by <code>key</code></p>
</li>
</ul>
</li>
<li><p><a name="buildQueryString"></a></p>
<h4 id="m-route-buildquerystring">m.route.buildQueryString</h4>
<p><strong>String buildQueryString(Object data)</strong></p>
<p>Serializes an object into its URI encoded querystring representation, following the same serialization conventions as <a href="https://medialize.github.io/URI.js/">URI.js</a></p>
<ul>
<li><p><strong>Object data</strong></p>
<p>An object to be serialized</p>
</li>
<li><p><strong>returns String querystring</strong></p>
<p>The serialized representation of the input data</p>
</li>
</ul>
</li>
<li><p><a name="parseQueryString"></a></p>
<h4 id="m-route-parsequerystring">m.route.parseQueryString</h4>
<p><strong>Object parseQueryString(String querystring)</strong></p>
<p>Deserializes an object from an URI encoded querystring representation, following the same deserialization conventions as <a href="https://medialize.github.io/URI.js/">URI.js</a></p>
<ul>
<li><p><strong>String querystring</strong></p>
<p>An URI encoded querystring to be deserialized</p>
</li>
<li><p><strong>returns Object data</strong></p>
<p>The deserialized object</p>
</li>
</ul>
</li>
</ul>
<hr>
<p><a name="redirecting"></a></p>
<h3 id="redirecting">Redirecting</h3>
<h4 id="usage">Usage</h4>
<p>You can programmatically redirect to another page. Given the example in the "Defining Routes" section:</p>
<pre><code class="lang-javascript">m.route("/dashboard/marysue");
</code></pre>
<p>redirects to <code>http://server/#/dashboard/marysue</code></p>
<hr>
<h4 id="signature">Signature</h4>
<p><a href="how-to-read-signatures.html">How to read signatures</a></p>
<pre><code class="lang-clike">void route(String path [, any params] [, Boolean shouldReplaceHistory])
</code></pre>
<ul>
<li><p><strong>String path</strong></p>
<p>The route to redirect to. Note that to redirect to a different page outside of the scope of Mithril's routing, you should use <code>window.location</code></p>
</li>
<li><p><strong>any params</strong></p>
<p>Parameters to pass as a querystring</p>
</li>
<li><p><strong>Boolean shouldReplaceHistory</strong></p>
<p>If set to true, replaces the current history entry, instead of adding a new one. Defaults to false.</p>
</li>
</ul>
<hr>
<p><a name="reading-current-route"></a></p>
<h3 id="reading-the-currently-active-route">Reading the currently active route</h3>
<h4 id="usage">Usage</h4>
<p>Mithril updates the native <code>location</code> object after rendering in order to allow the browser's <code>history.pushState</code> API to correctly show descriptive history entries (e.g. for Chrome's Ctrl+H page).</p>
<p>In order to retrieve the currently active route in a controller, you can use <code>m.route()</code>. This returns the portion of the URL determined by <code>m.route.mode</code> (minus the <code>?</code> or <code>#</code> symbols for the <code>search</code> and <code>hash</code> modes, respectively).</p>
<pre><code class="lang-javascript">//if the location bar is "http://example.com/?/foo/bar"
//and m.route.mode is `search`
//then `currentRoute == "/foo/bar"`
var currentRoute = m.route();
</code></pre>
<hr>
<h4 id="signature">Signature</h4>
<p><a href="how-to-read-signatures.html">How to read signatures</a></p>
<pre><code class="lang-clike">String route()
</code></pre>
<ul>
<li><p><strong>returns String route</strong></p>
<p>returns the currently active route</p>
</li>
</ul>
<hr>
<p><a name="mode-abstraction"></a></p>
<h3 id="mode-abstraction">Mode abstraction</h3>
<h4 id="usage">Usage</h4>
<p>This method is meant to be used with a virtual element's <code>config</code> attribute. For example:</p>
<pre><code class="lang-javascript">//Note that the '#' is not required in `href`, thanks to the `config` setting.
m("a[href='/dashboard/alicesmith']", {config: m.route});
</code></pre>
<p>This makes the href behave correctly regardless of which <code>m.route.mode</code> is selected. It's a good practice to always use the idiom above, instead of hardcoding <code>?</code> or <code>#</code> in the href attribute.</p>
<p>See <a href="mithril.html"><code>m()</code></a> for more information on virtual elements.</p>
<hr>
<h4 id="signature">Signature</h4>
<p><a href="how-to-read-signatures.html">How to read signatures</a></p>
<pre><code class="lang-clike">void route(DOMElement element, Boolean isInitialized, Object context, Object vdom)
</code></pre>
<ul>
<li><p><strong>DOMElement element</strong></p>
<p>an anchor element <code><a></code> with an <code>href</code> attribute that points to a route</p>
</li>
<li><p><strong>Boolean isInitialized</strong></p>
<p>the method does not run if this flag is set to true. This is to make the method compatible with virtual DOM elements' <code>config</code> attribute (see <a href="mithril"><code>m()</code></a>)</p>
</li>
<li><p><strong>Object context</strong></p>
<p>an object that retains its state across redraws</p>
</li>
<li><p><strong>Object vdom</strong></p>
<p>The virtual DOM data structure to which the config is applied to</p>
</li>
</ul>
</div>
</div>
</div>
</section>
</main>
<footer>
<div class="container">
Released under the <a href="http://opensource.org/licenses/MIT" target="_blank">MIT license</a>
<br />© 2014 Leo Horie
</div>
</footer>
<script src="lib/prism/prism.js"></script>
</body>
</html>