Reputation: 33
I have a member function in the object which gets the array of callback functions and the name of the event for which this function is set:
...
setHandlesByList: function (list) {
for (var i in list) {
var self = this;
$(document).on(list[i].name, function (e) {
list[i].callBack.call(self,e)
});
};
},
...
Somewhere in the child objects I have a call to this function of the parent object:
...
initClass: function () {
this.setHandlesByList([
{ name: 'configChecked', callBack: onConfigChecked },
{ name: 'configExpired', callBack: onConfigExpired },
]);
},
onConfigChecked: function() {
// some code
},
onConfigExpired: function() {
// some code
},
....
but something goes wrong - for all events the handler is the last set callback function...
Upvotes: 0
Views: 127
Reputation: 741
Try the following:
setHandlesByList: function (list) {
for ( var i = 0; i < list.length; i++ ) {
addCallback(list[i].name, list[i].callback);
}
function addCallback(on, name, callback) {
$(document).on(name, function(e) { callback.call(on, e); });
}
},
There is a problem with your scoping, because the value of i
eventually ends up being the last value of i
when your callbacks are evaluated.
Also note that you could use list.forEach
.
Upvotes: 3
Reputation: 1075875
Each event handler function you create in this code:
setHandlesByList: function (list) {
for (var i in list) {
var self = this;
$(document).on(list[i].name, function (e) {
list[i].callBack.call(self,e)
});
};
},
...has an enduring reference to list
and i
, not copies of them as of when the function is created. Since i
ends up being the last property enumerated, all handlers end up referring to the same list entry.
Instead, create a builder function to create the callback (sorry, I can't recreate the indentation style you use, I've just used a fairly standard one):
setHandlesByList: function (list) {
var self = this;
for (var i in list) {
$(document).on(list[i].name, buildHandler(list[i]));
};
function buildHandler(entry) {
return function (e) {
entry.callBack.call(self,e)
};
}
},
Now, the function created closes over entry
, the argument to the buildHandler
call, rather than over list
and i
. Since entry
(the argument) doesn't change, the handler works.
Note also that I've moved the var self = this;
out of the loop, as it didn't vary from iteration to iteration and so had no business being in the loop.
Side note: You've said that the function receives an array. If so, for-in
(with no safeguards) is not the correct way to loop through the entries in that array. More: Myths and realities of for..in
Upvotes: 2