Reputation: 438
I want to be able to use a bound event handler in prototype and retain my "this" context. But doing so seems to destroy the convenient default binding that prototype gives event handlers.
From the docs:
The handler's context (this value) is set to the extended element being observed (even if the event actually occurred on a descendent element and bubbled up).
That's exactly what I want. Once I bind the function to my own context, can I get access to this "element being observed" in any way? I can't depend on e.element() to give me the observed element (it could be a child element):
initialize: function() {
Event.observe('foo', 'click', this.addItem.bind(this));
},
...
addItem: function(e) {
e.element() // -> clicked element, not necessarily observed element
}
I know that there's a bindAsEventListener, but it doesn't seem to be necessary here and I don't see how I can access the targeted element once the function is bound.
I also am aware that there's an e.currentTarget, but that doesn't work in IE, does it?
Upvotes: 1
Views: 2525
Reputation: 729
When you use .bind
your reference to the observed element via this
is overwritten. If you have the following markup:
<div id="foo">
I am the Foo
<button id="bar">I am the Bar</button>
</div>
Without using .bind
you can access the observed & firing elements like so:
function greenEggsAndHam (evt) {
console.log('Observed Element: %o', this);
console.log('Clicked Element: %o', $(evt.element()));
}
Event.observe('foo', 'click', greenEggsAndHam);
However, if you want to use a class method as the event handler, and thus need to use .bind
, then the solution is to include the observed element's identifier as one of the arguments to the event handler when you first bind the event, like so:
var Test = Class.create({
initialize: function() {
Event.observe('foo', 'click', this.greenEggsAndHam.bind(this, 'foo'));
},
greenEggsAndHam: function (el, evt) {
console.log('Observed Element: %o', $(el));
console.log('Clicked Element: %o', $(evt.element()));
console.log('Class reference: %o', this);
}
});
var T = new Test();
That said, for sake of consistency I'd suggest you use .bindAsEventListener
instead of .bind
, and change your event handler to function (evt, el) {
so that the event object is the first argument and the observed element the second.
Upvotes: 2
Reputation: 1728
I too had this problem recently. My answer was to wrap the function in another function that does the work you need. I may have messed up the order but curry
will add this
to the args of the anonymous function and then you re-order from there.
initialize: function() {
Event.observe('foo', 'click',
function(e,that) { that.addItem(e,this); }.curry(this)
);
},
addItem: function(evt, evtElm) {
...
}
Upvotes: 0