It seems that kendo's unobtrusive-javascript style event calls break this
in my method context.
Say I have an object Foo
, instantiated as bar = new Foo()
function Foo(){};
Foo.prototype.name = "Herring";
Foo.prototype.doSomething = function(e) {
alert(this.name);
};
bar = new Foo();
And attach the event using data-click for example
<a data-role="button" data-click="bar.doSomething">Click Me</a>
Object context to bar
is replaced (not sure why, since we have the convenient element
container.) and so this.name
is undefined.
I've tried the old var self = this;
in the object constructor, but it's not working, does anyone know what the best way to solve this is?
Update : Hacky Workaround
Since I really don't want to lose the benefits of wrapping up my modules as classes, I've created event call functions wrappers, which then call the methods on the appropriate object.
For example, connect the markup to a wrapper-function.
<a data-role="button" data-click="doSomething">Click Me</a>
and the wrapper function just calls the object.method.
function doSomething(e){ bar.doSomething(e) };
Now, this achieves the intended result, but it's quite horrible, each and every event called from markup must have a proxy function like the one above. So just imagine a scenario where you have 300 events... and you'll instantly see why this is horrible.
If there's no other solution, and I dearly hope there is. I'll post this workaround as an answer, but as far as I'm concerned, it's far from desirable.
Footnote
I'll be completely honest this seems like major architectural flaw in Kendo, since this method of calling events from markup is "the kendo way." Obviously it can't be patched out, because there's probably a fair bit of code already dealing with this
as a reference to the html element.
Being able to override it, or being able to route these event calls through a generic handler which can pass the call on, essentially a generic proxy function, are possible ways this could be dealt with. It could also be a simple configurable value on the kendo.
object.
Theoretical Solution
I'll post follow-up if this works, in theory it's possible to throw events at a generic proxy, and have it call the properly scoped function.
Say we use the event attribute to call the proxy and then create a separate attribute to convey the object/method call. For example.
<a data-role="button" data-click="prox" data-prox="o.eventHandler">Click Me</a>
The proxy function would pull prox
from the attribute dataset:
method - using eval
Not because I'm evil, but needs must.
// sitting in global namespace
function prox(e){
var p = e.sender.element.data['prox'];
// make sure our delegate is a function.
if("function" == eval("typeof "+p)) {
eval(p + "(e)");
}
}
Obviously I'd like a better way to do this but, at least it's DRY.
(I'll cook a non-eval method in a moment...)
Begone Eval...
let's use the window context to locate the object / method.
function prox(e) {
var p = e.sender.element.data['prox'];
if(p.indexOf(".") == -1){
// global function : where *this* is window.
// check you've got the function if not ditch it.
if("function" == typeof window[p]) window[p](e);
} else {
// object/method (one level deep only.)
var s = p.split(".");
var o = s[0], m = s[1];
// check the object/method is a function before executing it.
if("function" == typeof window[o][p]) window[o][p](e);
}
}
Of course for global (window) scoped functions, this as the element is probably more useful, but in that case, you have a choice, I'd leave out the