-
Notifications
You must be signed in to change notification settings - Fork 44
/
Copy pathmithril.module.html
210 lines (193 loc) · 9.82 KB
/
mithril.module.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
<!doctype html>
<html>
<head>
<title>Mithril</title>
<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">Blog</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.1.21)</h2>
<h3 id="core">Core</h3>
<ul>
<li><a href="mithril.html">m</a></li>
<li><a href="mithril.prop.html">m.prop</a></li>
<li><a href="mithril.withAttr.html">m.withAttr</a></li>
<li><a href="mithril.module.html">m.module</a></li>
<li><a href="mithril.trust.html">m.trust</a></li>
<li><a href="mithril.render.html">m.render</a></li>
<li><a href="mithril.redraw.html">m.redraw</a>
<ul>
<li><a href="mithril.redraw.html#strategy">m.redraw.strategy(strategy)</a></li>
</ul>
</li>
</ul>
<h3 id="routing">Routing</h3>
<ul>
<li><a href="mithril.route.html">m.route</a>
<ul>
<li><a href="mithril.route.html#defining-routes">m.route(rootElement, defaultRoute, routes)</a></li>
<li><a href="mithril.route.html#redirecting">m.route(path, params)</a></li>
<li><a href="mithril.route.html#reading-current-route">m.route()</a></li>
<li><a href="mithril.route.html#mode-abstraction">m.route(element)</a></li>
<li><a href="mithril.route.html#mode">m.route.mode</a></li>
<li><a href="mithril.route.html#param">m.route.param</a></li>
</ul>
</li>
</ul>
<h3 id="data">Data</h3>
<ul>
<li><a href="mithril.request.html">m.request</a></li>
<li><a href="mithril.deferred.html">m.deferred</a></li>
<li><a href="mithril.sync.html">m.sync</a></li>
<li><a href="mithril.computation.html">m.startComputation / m.endComputation</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-module">m.module</h2>
<p>A module is an Object with two keys: <code>controller</code> and <code>view</code>. Each of those should point to a Javascript function.</p>
<p>When using <code>m.module</code>, Mithril instantiates controllers as if they were class constructors. However, controllers may return objects if you want to use that Javascript feature to have more fine-grained control over a controller's lifecycle.</p>
<p>Conceptually, the easiest way to think of a module is as a logical namespace with which to organize applications. For example, an app might have a dashboard module, a userEditForm module, an autocompleter module, a date formatting module, etc</p>
<p>In the context of single page applications (SPA), a module can often be thought of as the code for a single "page", i.e. a visual state that is bookmarkable. Module can, however, also represent <em>parts</em> of pages.</p>
<p>Note that a module might have external dependencies and that the dependencies aren't considered part of the module.</p>
<p>In more complex applications, modules can be nested in a <a href="http://en.wikipedia.org/wiki/Hierarchical_model%E2%80%93view%E2%80%93controller">hierarchical MVC</a> pattern. Nested reusable modules that have views are called <strong>Components</strong>.</p>
<p>Modules and namespaces are often used interchangeably, but namespaces that do not implement the module interface (that is, objects that do not have a property called <code>controller</code> and a property called <code>view</code>) cannot be activated with <code>m.module</code>. For example, a namespace for date formatting utilities could be labeled a "module" (in the generic sense of the word) but it would not contain a view class, and therefore attempting to initialize it via <code>m.module</code> would result in undefined behavior.</p>
<hr>
<h3 id="usage">Usage</h3>
<p>You can make anonymous modules out of existing classes</p>
<pre><code class="lang-javascript">//controller class
var dashboardController = function() {
this.greeting = "Hello";
};
//view class
var dashboardView = function(ctrl) {
return m("h1", ctrl.greeting);
};
//initialize an anonymous module
m.module(document.body, {controller: dashboardController, view: dashboardView});</code></pre>
<p>Typically, however, modules and namespaces are used interchangeably.</p>
<pre><code class="lang-javascript">//`dashboard` is both a namespace and a module
var dashboard = {}
//controller class
dashboard.controller = function() {
this.greeting = "Hello";
};
//view class
dashboard.view = function(ctrl) {
return m("h1", ctrl.greeting);
};
//initialize it
m.module(document.body, dashboard);</code></pre>
<p>The example below shows a component module called <code>user</code> being included in a parent module <code>dashboard</code>.</p>
<pre><code class="lang-javascript">//this is a sample module
var dashboard = {
controller: function() {
this.greeting = "Hello";
this.user = new user.controller();
},
view: function(controller) {
return [
m("h1", controller.greeting),
user.view(controller.user)
];
}
};
//this module is being included as a component
var user = {
//model
User: function(name) {
this.name = name;
},
//controller
controller: function() {
this.user = new user.User("John Doe");
},
//view
view: function(controller) {
return m("div", controller.user.name);
}
};
//activate the dashboard module
m.module(document.body, dashboard);</code></pre>
<p>yields:</p>
<pre><code class="lang-markup"><body>
<h1>Hello</h1>
<div>John Doe</div>
</body></code></pre>
<h3 id="unloading-modules">Unloading modules</h3>
<p>If a module's controller implements an instance method called <code>onunload</code>, this method will be called when a new <code>m.module</code> call updates the root DOM element tied to the module in question.</p>
<pre><code class="lang-javascript">var module1 = {};
module1.controller = function() {
this.onunload = function() {
console.log("unloading module 1");
};
};
module1.view = function() {};
m.module(document, module1);
var module2 = {};
module2.controller = function() {};
module1.view = function() {};
m.module(document, module2); // logs "unloading module 1"</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>
<p>You can also use this event to prevent a module from being unloaded (e.g. to alert a user to save their changes before navigating away from a page)</p>
<pre><code class="lang-javascript">var module1 = {}
module1.controller = function() {
this.onunload = function(e) {
if (!confirm("are you sure you want to leave this page?")) e.preventDefault()
}
}</code></pre>
<hr>
<h3 id="signature">Signature</h3>
<p><a href="how-to-read-signatures.html">How to read signatures</a></p>
<pre><code class="lang-clike">void module(DOMElement rootElement, Module module)
where:
Module :: Object { Controller, void view(Object controllerInstance) }
Controller :: void controller() | void controller() { prototype: void unload(UnloadEvent e) }
UnloadEvent :: Object {void preventDefault()}</code></pre>
<ul>
<li><p><strong>DOMElement rootElement</strong></p>
<p>A DOM element which will contain the view's template.</p>
</li>
<li><p><strong>Module module</strong></p>
<p>A module is supposed to be an Object with two keys: <code>controller</code> and <code>view</code>. Each of those should point to a Javascript class constructor function</p>
<p>The controller class is instantiated immediately upon calling <code>m.module</code>.</p>
<p>Once the controller code finishes executing (and this may include waiting for AJAX requests to complete), the view class is instantiated, and the instance of the controller is passed as an argument to the view's constructor.</p>
<p>Note that controllers can manually instantiate child controllers (since they are simply Javascript constructors), and likewise, views can instantiate child views and manually pass the child controller instances down the the child view constructors.</p>
<p>This "<a href="https://en.wikipedia.org/wiki/Turtles_all_the_way_down">turtles all the way down</a>" approach is the heart of Mithril's component system.</p>
<p>Components are nothing more than decoupled classes that can be dynamically brought together as required. This permits the swapping of implementations at a routing level (for example, if implementing widgetized versions of existing components), and class dependency hierarchies can be structurally organized to provide uniform interfaces (for unit tests, for example).</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>