Javascript modules with custom events

At some point when writing javascript modules you will want to start passing data between the modules.

1) One method is to hard wire the names of the callbacks but this creates dependancies and is obviously terrible e.g.

function load(data) {
    // do something here
    example.complete(data);
}

2) The second method is to pass through your callback through the chain until it's required e.g.


function load(data, callback) {
    // do something here
    callback(data);
}
function complete(items) {
    console.log('complete', items);
}

load({example:'test'}, complete);

However this is a one to one relationship, e.g. one callback to one function call. So if you want to pass the data through to multiple parts of your application then you would need a parent function which links them all together.

3) The ideal solution is to have a publish/subscribe pattern which allows you to subscribe to an event and receive updates whenever it's called. This can push updated to any number of callbacks and can be added and removed dynamically  giving you full control over your modules and events.

Here's a module that does exactly that, by saving every callback in an object using the event name as a key:


define('Events', {
    events: {},
    addEvent: function(name, callback) {
        if (!this.events[name]) { this.events[name] = []; }
        this.events[name].push(callback);
    },
    removeEvent: function(name, callback) {
        if (this.events[name]) {
            if (callback) {
                for (var i=0; i<this.events[name].length; ++i) {
                    if (this.events[name][i] === callback) { this.events[name].splice(i, 1); return true; }
                }
            }
            else { delete this.events[name]; }
        }
    },
    dispatchEvent: function(name, data) {
        if (this.events[name]) {
            for (var i=0; i<this.events[name].length; ++i) {
                this.events[name][i]({ data: data, target: this, type: name});
            }
        }
    }
});


If every module you create contains these functions you can chain any module to another using the following pattern. e.g.


define('Example', {
    extend: 'Events',
    init: function() {
        this.items = {item: 'testdata'};
    },
    load: function() {
        this.dispatchEvent('complete', this.items);
    }
});



var example = new Example('example1', {param: 'options'});
example.addEvent('complete', function(e) {
    console.log('oncomplete removed', e);
});

example.removeEvent('complete');

example.addEvent('complete', function(e) {
    console.log('oncomplete added again', e);
});
example.load();

Easy to use event creation, deletion and dispatching in 24 lines of code. Here's a working full example using my base module class:
https://github.com/kmturley/js-modules

No comments:

Post a Comment