160 lines
No EOL
8.4 KiB
HTML
160 lines
No EOL
8.4 KiB
HTML
<!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">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="core-topics">Core Topics</h2>
|
|
<ul>
|
|
<li><a href="installation.html">Installation</a></li>
|
|
<li><a href="getting-started.html">Getting Started</a></li>
|
|
<li><a href="routing.html">Routing</a></li>
|
|
<li><a href="web-services.html">Web Services</a></li>
|
|
<li><a href="components.html">Components</a></li>
|
|
</ul>
|
|
<h2 id="advanced-topics.html">Advanced Topics</h2>
|
|
<ul>
|
|
<li><a href="auto-redrawing.html">The Auto-Redrawing System</a></li>
|
|
<li><a href="integration.html">Integrating with Other Libraries</a></li>
|
|
<li><a href="compiling-templates.html">Compiling Templates</a></li>
|
|
</ul>
|
|
<h2 id="misc">Misc</h2>
|
|
<ul>
|
|
<li><a href="comparison.html">Differences from Other MVC Frameworks</a></li>
|
|
<li><a href="benchmarks.html">Benchmarks</a></li>
|
|
<li><a href="practices.html">Good Practices</a></li>
|
|
<li><a href="tools.html">Useful Tools</a></li>
|
|
</ul>
|
|
</div>
|
|
<div class="col(9,9,12)">
|
|
<h2 id="integrating-with-other-libraries">Integrating with Other Libraries</h2>
|
|
<p>Integration with third party libraries or vanilla javascript code can be achieved via the <a href="mithril.html#accessing-the-real-dom"><code>config</code> attribute of virtual elements</a>.</p>
|
|
<p>It's recommended that you encapsulate integration code in a component or a helper function.</p>
|
|
<p>The example below shows a simple component that integrates with the <a href="http://ivaynberg.github.io/select2/">select2 library</a>.</p>
|
|
<pre><code class="lang-javascript">//Select2 component (assumes both jQuery and Select2 are included in the page)
|
|
|
|
/** @namespace */
|
|
var select2 = {};
|
|
|
|
/**
|
|
select2 config factory. The params in this doc refer to properties of the `ctrl` argument
|
|
@param {Object} data - the data with which to populate the <option> list
|
|
@param {number} value - the id of the item in `data` that we want to select
|
|
@param {function(Object id)} onchange - the event handler to call when the selection changes.
|
|
`id` is the the same as `value`
|
|
*/
|
|
select2.config = function(ctrl) {
|
|
return function(element, isInitialized) {
|
|
var el = $(element);
|
|
|
|
if (!isInitialized) {
|
|
//set up select2 (only if not initialized already)
|
|
el.select2()
|
|
//this event handler updates the controller when the view changes
|
|
.on("change", function(e) {
|
|
//integrate with the auto-redrawing system...
|
|
m.startComputation();
|
|
|
|
//...so that Mithril autoredraws the view after calling the controller callback
|
|
if (typeof ctrl.onchange == "function") ctrl.onchange(el.select2("val"));
|
|
|
|
m.endComputation();
|
|
//end integration
|
|
});
|
|
}
|
|
|
|
//update the view with the latest controller value
|
|
el.select2("val", ctrl.value);
|
|
}
|
|
}
|
|
|
|
//this view implements select2's `<select>` progressive enhancement mode
|
|
select2.view = function(ctrl) {
|
|
return m("select", {config: select2.config(ctrl)}, [
|
|
ctrl.data.map(function(item) {
|
|
return m("option", {value: item.id}, item.name)
|
|
})
|
|
]);
|
|
};
|
|
|
|
//end component
|
|
|
|
|
|
|
|
//usage
|
|
var dashboard = {};
|
|
|
|
dashboard.controller = function() {
|
|
//list of users to show
|
|
this.data = [{id: 1, name: "John"}, {id: 2, name: "Mary"}, {id: 3, name: "Jane"}];
|
|
|
|
//select Mary
|
|
this.currentUser = this.data[1];
|
|
|
|
this.changeUser = function(id) {
|
|
console.log(id)
|
|
};
|
|
}
|
|
|
|
dashboard.view = function(ctrl) {
|
|
return m("div", [
|
|
m("label", "User:"),
|
|
select2.view({data: ctrl.data, value: ctrl.currentUser.id, onchange: ctrl.changeUser})
|
|
]);
|
|
}
|
|
|
|
m.module(document.body, dashboard);</code></pre>
|
|
<p><code>select2.config</code> is a factory that creates a <code>config</code> function based on a given controller. We declare this outside of the <code>select2.view</code> function to avoid cluttering the template.</p>
|
|
<p>The <code>config</code> function created by our factory only runs the initialization code if it hasn't already. This <code>if</code> statement is important, because this function may be called multiple times by Mithril's auto-redrawing system and we don't want to re-initialize select2 at every redraw.</p>
|
|
<p>The initialization code defines a <code>change</code> event handler. Because this handler is not created using Mithril's templating engine (i.e. we're not defining an attribute in a virtual element), we must manually integrate it to the auto-redrawing system.</p>
|
|
<p>This can be done by simply calling <code>m.startComputation</code> at the beginning, and <code>m.endComputation</code> at the end of the function. You must add a pair of these calls for each asynchronous execution thread, unless the thread is already integrated.</p>
|
|
<p>For example, if you were to call a web service using <code>m.request</code>, you would not need to add more calls to <code>m.startComputation</code> / <code>m.endComputation</code> (you would still need the first pair in the event handler, though).</p>
|
|
<p>On the other hand, if you were to call a web service using jQuery, then you would be responsible for adding a <code>m.startComputation</code> call before the jQuery ajax call, and for adding a <code>m.endComputation</code> call at the end of the completion callback, in addition to the calls within the <code>change</code> event handler. Refer to the <a href="auto-redrawing.html"><code>auto-redrawing</code></a> guide for an example.</p>
|
|
<p>One important note about the <code>config</code> method is that you should avoid calling <code>m.redraw</code>, <code>m.startComputation</code> and <code>m.endComputation</code> in the <code>config</code> function's execution thread. (An execution thread is basically any amount of code that runs before other asynchronous threads start to run.)</p>
|
|
<p>While Mithril technically does support this use case, relying on multiple redraw passes degrades performance and makes it possible to code yourself into an infinite execution loop situation, which is extremely difficult to debug.</p>
|
|
<p>The <code>dashboard</code> module in the example shows how a developer would consume the select2 component.</p>
|
|
<p>You should always document integration components so that others can find out what attribute parameters can be used to initialize the component.</p>
|
|
<hr>
|
|
<h2 id="integrating-to-legacy-code">Integrating to legacy code</h2>
|
|
<p>If you need to add separate widgets to different places on a same page, you can simply initialize each widget as you would a regular Mithril application (i.e. use <code>m.render</code>, <code>m.module</code> or <code>m.route</code>).</p>
|
|
<p>There's just one caveat: while simply initializing multiple "islands" in this fashion works, their initialization calls are not aware of each other and can cause redraws too frequently. To optimize rendering, you should add a <code>m.startComputation</code> call before the first widget initialization call, and a <code>m.endComputation</code> after the last widget initialization call in each execution thread.</p>
|
|
<pre><code>m.startComputation()
|
|
|
|
m.module(document.getElementById("widget1-container"), widget1)
|
|
|
|
m.module(document.getElementById("widget2-container"), widget1)
|
|
|
|
m.endComputation()</code></pre>
|
|
|
|
</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> |