Wiring Up Events With Dynamic Singletons
In some webapps, it's possible to have singleton objects that get instantiated once but initialized often. For instance (assume jQuery):
(function(window){
window.MyNamespace = window.MyNamespace || {};
var MySingleton = MyNamespace.MySingleton = {
init: function() {
//init code
}
}
MySingleton.init(); //init on load
})(window);
The above code adds a singleton to your global namespace (which can be referenced by MyNamespace.MySingleton elsewhere in your code). A lot of times, in the init() function, event binding takes place:
init: function() {
this.elem = $('#myelem');
//wire events to this specific element
this.elem
.on('click', '.myclass1', this.handleClick)
.on('change', '.myclass2', this.handleChange)
//etc
;
//wire events to doc, like triggered custom events
$(document)
.on('customevent', this.handleCustomEvent)
//etc
;
}
This is fine if your objects main element sticks around in the DOM and your singleton is not re-init-ed. But what if you have a webapp that dynamically loads your HTML, replacing whatever was there before? Your DOM elements will successfully rebind (assuming you have fresh DOM elements), but your document events will get re-bound, meaning they will react an increasing number of times as users flip through your app.
Handling this is simple: create a hasBound property on your singleton (simplified example):
var MySingleton = {
hasBound: false
, init: function() {
// [ DOM wireup ]
if (!this.hasBound) {
// [ document wireup ]
this.hasBound = true;
}
}
}
Now you can safely re-init your singleton without worrying about multi-binding your events!
Written by Jason Edelman
Related protips
Have a fresh tip? Share with Coderwall community!
JavaScript on a page runs with the privileges of that origin. One altered library, tag manager, or snippet can read inputs, change what people see, and call your APIs as the user.
Security insights from Cside