From 72c039c4dc1496bf667ab046fe1c64292b8dfc69 Mon Sep 17 00:00:00 2001 From: pelonpelon Date: Sat, 1 Aug 2015 14:51:18 -0500 Subject: [PATCH 1/2] allow m.withAttr callback to determine it's own `this` [non-breaking change] Background: In ES6 we now have `Object.setPrototypeOf` which makes prototype delegation an alternative to *sugary*, fake class coding patterns. This can be accomplished in ES5, but ES6 is much more elegant. Here is a basic example. `new` is never used and `this` is very easy to follow. Working example with changes to mithril.js on lines 854, 858, 859 *only*. http://jsbin.com/nopugo/1/edit?js,console,output ```javascript 'use strict' const m = require('mithril') const DataModel = { data: [1,2,3], getData(){ console.log('getting data from server') return this.data }, postData(val){ console.log('sending data to server') this.data.push(val) } } const ViewModel = { filterEvenData: function() { return this.getData().filter((val) => (val % 2 === 0) && (+val !== 0)) }, addNewData: function(val){ console.log('adding new data', val) this.postData(val) } } var Model = Object.setPrototypeOf(ViewModel, DataModel) const App = { controller(){}, view(ctrl){ return m('div', [ m('pre', [ 'EVEN NUMBERS IN DATA\n', this.filterEvenData().map((key,i) =>`${i+1} = ${key}\n`) ]), m('div', 'Enter a number'), m('input[placeholder=number]', { // addNewData is called with **this** === undefined unless we pass `this` to Function.prototype.call in m.withAttr onchange: m.withAttr('value', App.addNewData, App), value: null } ) ]) } } Object.setPrototypeOf(App, Model) m.mount(document.body, App) ``` --- mithril.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mithril.js b/mithril.js index 080c6052..a58e2fc3 100644 --- a/mithril.js +++ b/mithril.js @@ -851,11 +851,12 @@ var m = (function app(window, undefined) { else m.endComputation(); } - m.withAttr = function(prop, withAttrCallback) { + m.withAttr = function(prop, withAttrCallback, callbackThis) { return function(e) { e = e || event; var currentTarget = e.currentTarget || this; - withAttrCallback(prop in currentTarget ? currentTarget[prop] : currentTarget.getAttribute(prop)); + var _this = callbackThis || this; + withAttrCallback.call(_this, prop in currentTarget ? currentTarget[prop] : currentTarget.getAttribute(prop)); }; }; From 352d093d90857c064e485beb33b6904bc0eeec1f Mon Sep 17 00:00:00 2001 From: pelonpelon Date: Sat, 1 Aug 2015 15:01:38 -0500 Subject: [PATCH 2/2] test for correct `this` on m.withAttr callback --- tests/mithril-tests.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/mithril-tests.js b/tests/mithril-tests.js index 36c50785..f1597309 100644 --- a/tests/mithril-tests.js +++ b/tests/mithril-tests.js @@ -1380,6 +1380,13 @@ function testMithril(mock) { handler({currentTarget: {test: "foo"}}) return value === "foo" }) + test(function() { + var value + var _this + var handler = m.withAttr("test", function(data) {value = data}, _this) + handler({currentTarget: {test: "foo"}}) + return value === "foo" && handler.this === _this + }) //m.trust test(function() {return m.trust("test").valueOf() === "test"})