Vishful thinking…

Writing better javascript – Part 8

Posted in javascript by viswaug on November 21, 2008

JavaScript event model

This is another practice I have adopted in my JavaScript development to enable the components I create be able to raise custom events and have an event model that will support consumers to be able to use them as needed. That said, please do let me know if this event model can be improved upon in anyway possible. Always open to comments and suggestions…

In the code illustration below, I am adding the ‘click’, ‘select’, ‘unselect’, ‘enable’ and ‘disable’ event support to my MapTool JavaScript component. If you have been building mapping application then it should be evident why I would need those events on my map tools. I create a private listeners object where I store the listeners for every supported event as properties with the same name as that of the event. That makes it a little easier to retrieve the array of listeners for a certain named event. I also throw an error if the user tries to add a listener to an event that has not been pre-defined. This is obviously optional and be handled a couple of different ways. If the user tries to add a listener to an event that has not been pre-defined, the add listener call can just be ignored or a new event with that name can be added to the listeners object (but I don’t have such requirements in my applications so I throw an error). I also use the code snippet from John Resig (jQuery’s father) to be able to remove items from an array. That function can also be added to the array prototype if you are comfortable with messing the Array prototype.

var MapTool = function(toolID, options) {
    //private properties
    var _listeners = new Object(); //Create an object that hold the arrays of listeners as its properties
    //Predefine known events on the object – optional
    _listeners.click = new Array();
    _listeners.select = new Array();
    _listeners.unselect = new Array();
    _listeners.enable = new Array();
    _listeners.disable = new Array();

    //Adding John Resig’s array remove function
    _removeFromArray = function(array, from, to) {
        var rest = array.slice((to || from) + 1 || array.length);
        array.length = from < 0 ? array.length + from : from;
        return array.push.apply(array, rest);
    };
    //

    var _raiseEvent = function(eventName, e) {
        if (_listeners[eventName]) {
            for (var i = 0; i < _listeners[eventName].length; i++) {
                if (_listeners[eventName][i]) {
                    _listeners[eventName][i](e);
                }
            }
        }
    };

    var _clearListeners = function(eventName) {
        if (_listeners[eventName]) {
            _listeners[eventName] = new Array();
        }
    };

    return {
        createListener: function(eventName) {
            if (!_listeners[eventName]) {
                _listeners[eventName] = new Array();
            }
        },

        addListener: function(eventName, listener) {
            if(typeof(eventName) !== ‘string’ || typeof(listener) !== ‘function’) {
                if (!_listeners[eventName]) {
                    throw “The event ‘” + eventName + “‘ is not supported by MapTool.”;
                    //_listeners[eventName] = new Array(); – this is another option if you don’t want to throw an error if the user tries to add a listener for an unknown event
                }
                return { name: eventName, index: _listeners[eventName].push(listener) };
            }
            else {
                throw “Cannot add event listener. Invalid argument. A valid event name and listener function is required.”;
            }
        },

        removeListener: function(eventObj) {
            if (eventObj && eventObj.name && (eventObj.index || eventObj.index === 0)) {
                if (_listeners[eventObj.name]) {
                    _removeFromArray(_listeners[eventObj.index], index);
                }
            }
            else {
                throw “Cannot remove listener. Inavalid event listener object.”;
            }
        }
    };
};

 

The above event model has been working pretty good for me and the requirements in my applications.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: