abidibo.net

Javascript event dispatcher

javascript programming

Update 11/2017

This ideas finally became a npm package: js-event-dispatcher

Introduction

Too much time has passed since my last post, so today I'll write about a simple javascript component, an event dispatcher which allows two entities to communicate each other.

The simplest use case I can think of is the one in which we have an object which emits an event and another object which should listen to such event.

We could implement all the stuff without the event dispatcher, but then the two entities need to be coupled in some ways, whether using such dispatcher we can decouple our two objects.

Demo

See the demo on codepen.io

The code

Ok, this is vanilla javascript:

var EventDispatcher = {
  listeners: {},
  register: function(evt_name, callback) {
    if(typeof this.listeners[evt_name] == 'undefined') {
      this.listeners[evt_name] = [];
    }
    this.listeners[evt_name].push(callback);
  },
  emit: function(evt_name, params) {
    if(typeof this.listeners[evt_name] != 'undefined') {
      for(var i = 0, l = this.listeners[evt_name].length; i < l; i++) {
        this.listeners[evt_name][i].call(this, evt_name, params);
      }
    }
  }
}

As you can see the object provides two methods: register and emit. The first used to register an object in order to listen to events, the second used to emit an event.

Now let's see an example of usage, imagine we have two objects, object1 has to be notified (and consequentially should do something) when object1 captures an event myevent:

EventDispatcher.register('myevent', object1.dosomething);
// inside an object2 method
EventDispatcher.emit('myevent', { custom: 'parameter' });

So the dosomething method of object1 is called with arguments 'myevent' and { custom: 'parameter' }. As you see object2 doesn't need to know how object1 is made, nor has to know that object1 has a dosomething method, it just emits the event. The only necessary thing here is that object1 should know which kind of parameter will receive from that event.

That's all, as usual comments are appreciated.

Edit 2014-01-17

Comments are useful!

@panzi makes me notice that the above code fails when the event name is equal to one of the js Object properties, as 'toString' or 'hasOwnProperty', and he posted a link which solves such problems.

There is also another way, I think, to solve the matter.
My solution consists in the addition of an event name prefix managed internally by the EventDispatcher, so here comes the rewritten code. I've also added a bind parameter in order to define the context of the callback function when registering the listener, if set to null then the context is set to be the EventDispatcher object.

var EventDispatcher = {
  _prefix: 'on_',
  listeners: {},
  register: function(evt_name, bind, callback) {
    var _evt_name = this._prefix + evt_name;
    if(typeof this.listeners[_evt_name] == 'undefined') {
      this.listeners[_evt_name] = [];
    }
    this.listeners[_evt_name].push([bind === null ? this : bind, callback]);
  },
  emit: function(evt_name, params) {
    var _evt_name = this._prefix + evt_name;
      if(typeof this.listeners[_evt_name] != 'undefined') {
        for(var i = 0, l = this.listeners[_evt_name].length; i < l; i++) {
          this.listeners[_evt_name][i][1].call(this.listeners[_evt_name][i][0], evt_name, params);
        }
      }
  }
}

That's all, till next modification of course.

Subscribe to abidibo.net!

If you want to stay up to date with new contents published on this blog, then just enter your email address, and you will receive blog updates! You can set you preferences and decide to receive emails only when articles are posted regarding a precise topic.

I promise, you'll never receive spam or advertising of any kind from this subscription, just content updates.

Subscribe to this blog

Comments are welcome!

blog comments powered by Disqus

Your Smartwatch Loves Tasker!

Your Smartwatch Loves Tasker!

Now available for purchase!

Featured