Last Updated: February 25, 2016
·
942
· ultimatedelman

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!