I have a chunk of markup in my page that represents a view, and a JS controller function which is associated with that view. (These are Angular, but I don't believe that matters.) The controller code listens for a custom event fired from elsewhere in the app, and handles that event with some controller-specific logic.
My problem is that the controller's event handler is getting attached too many times: it gets attached every time the view is re-activated, resulting in the handler being run multiple times every time the custom event is fired. I only want the handler to run once per event.
I've tried using .off() to unbind the handler before binding it; I've tried .one() to ensure that the handler is only run once; and I've tried $.proxy() after reading about its interaction with .off() here.
Here's a sketch of my code:
// the code inside this controller is re-run every time its associated view is activated
function MyViewController() {
/* SNIP (lots of other controller code) */
function myCustomEventHandler() {
console.log('myCustomEventHandler has run');
// the code inside this handler requires the controller's scope
}
// Three variants of the same misbehaving event attachment logic follow:
// first attempt
$('body').off('myCustomEvent', myCustomEventHandler);
$('body').on('myCustomEvent', myCustomEventHandler);
// second attempt
$('body').one('myCustomEvent', myCustomEventHandler);
// third attempt
$('body').off('myCustomEvent', $.proxy(myCustomEventHandler, this));
$('body').on('myCustomEvent', $.proxy(myCustomEventHandler, this));
// all of these result in too many event attachments
};
// ...meanwhile, elsewhere in the app, this function is run after a certain user action
function MyEventSender() {
$('body').trigger('myCustomEvent');
console.log('myCustomEvent has been triggered');
};
After clicking around in my app and switching to the troublesome view five times, then doing the action which runs MyEventSender, my console will look like this:
myCustomEvent has been triggered
myCustomEventHandler has run
myCustomEventHandler has run
myCustomEventHandler has run
myCustomEventHandler has run
myCustomEventHandler has run
How can I get it to look like this:
myCustomEvent has been triggered
myCustomEventHandler has run
???
$(function() { ... })call.