Last active
August 3, 2016 21:19
-
-
Save gilbert/0bf02f1f21c72de9fb49 to your computer and use it in GitHub Desktop.
Mithril.js - Avoiding m.props
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// m.prop is a great pattern, but Plain-old JavaScript Objects (POJO) are | |
// much more pleasant to work with. | |
// Here's an example of using POJOs with one- and two-way data binding. | |
// First, the helper methods | |
m.setValue = function (obj, prop) { | |
return m.withAttr('value', function(value) { obj[prop] = value }) | |
} | |
// This helper isn't necessary if you're using ES6 | |
m.set = function (obj, prop, value) { | |
return function () { obj[prop] = value } | |
} | |
// | |
// Usage Example #1 | |
// | |
var CommentBox = {} | |
CommentBox.controller = function () { | |
var ctrl = this | |
ctrl.userInput = '' // No m.prop! | |
} | |
CommentBox.view = function (ctrl) { | |
return m('.comment-box', [ | |
m('h1', "Please enter your comment:"), | |
m('textarea', { onchange: m.setValue(ctrl, 'userInput') }, ctrl.userInput) | |
]) | |
} | |
// | |
// Usage Example #2 | |
// | |
var TabbedContent = {} | |
TabbedContent.controller = function () { | |
var ctrl = this | |
ctrl.tab = 'first' // No m.prop! | |
} | |
TabbedContent.view = function (ctrl) { | |
return m('.tabs', [ | |
m('.tab', { onclick: m.set(ctrl, 'tab', 'first') }, "First Tab"), | |
m('.tab', { onclick: m.set(ctrl, 'tab', 'second') }, "Second Tab"), | |
// ES6 version | |
// m('.tab', { onclick: () => ctrl.tab = 'first') }, "First Tab"), | |
// m('.tab', { onclick: () => ctrl.tab = 'second') }, "Second Tab"), | |
ctrl.tab === 'first' ? m('h1', "Content 1") : null, | |
ctrl.tab === 'second' ? m('h1', "Content 2") : null | |
]) | |
} | |
// | |
// Usage Example #3 - Sharing state between siblings | |
// | |
var Parent = {} | |
Parent.controller = function () { | |
this.names = ['Alice', 'Bob'] | |
} | |
Parent.view = function (ctrl) { | |
return [ m(SiblingA, { names: ctrl.names }), m(SiblingB, { names: ctrl.names }) ] | |
} | |
var SiblingA = { | |
view: function (ctrl, options) { | |
return m('ul.sib-a', options.names.map(function (name) { | |
return m('li', name) | |
})) | |
} | |
} | |
var SiblingB = { | |
view: function (ctrl, options) { | |
return m('.sib-b', [ | |
m('button', { | |
onclick: function (e) { | |
var newName = prompt("Please enter a new name:") | |
names.push(newName) | |
} | |
}, "Add name") | |
]) | |
} | |
} | |
// | |
// Usage Example #4 - Sharing primitives between siblings | |
// | |
var Parent = {} | |
Parent.controller = function () { | |
this.data = { x: 10, y: 20 } | |
} | |
Parent.view = function (ctrl) { | |
return [ m(SiblingA, { shared: ctrl.data }), m(SiblingB, { shared: ctrl.data }) ] | |
} | |
var SiblingA = { | |
view: function (ctrl, options) { | |
return m('p', "x: " + options.shared.x, "y: " + options.shared.y) | |
} | |
} | |
var SiblingB = { | |
view: function (ctrl, options) { | |
return m('.sib-b', [ | |
m('button', { | |
onclick: function (e) { | |
var newX = prompt("Please enter a new x value:") | |
options.shared.x = parseInt(newX, 10) | |
} | |
}, "Change x") | |
]) | |
} | |
} |
@panych That is actually a common misconception. m.prop
is only a getter / setter; it has no ties to the redraw system.
You are right, it's true for Mithril 0.2.x. But m.prop
in the upcoming major version of Mithril ("rewrite" brunch) will produce a stream, which brings features, like computed values.
Yes, using the stream version of m.prop
will be much more useful... but only when you need it. Always reach for simple before complex! :)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
As I know, Mithril uses
m.prop
not only to support getter/setter pattern, but for controlling auto redrawing system.