Obey and Report – A JavaScript Event Emitter Pattern

by Nicolas Bevacqua on November 11, 2013

The modern web is always changing, and this article is more than two years old.

By Nicolas Bevacqua

The event emitter pattern was popularized by Node and is made available in the browser by libraries such as EventEmitter2. In practice, I haven’t seen a lot of use of event emitters in client-side applications, but lately I’ve been applying it more and more in my code. Here, I’ll introduce a modular approach to client-side development I didn’t invent, but which I decided to name anyway.

Obey and Report

Recently, I came up with this idea where I laid out a library that doesn’t necessarily depend on Angular, but which plays very nicely with it. The pattern basically dictates that the components can only change their state through commands, which can come from either its UI directly or be programatically invoked. This allows me to provide a default UI for the component, but is flexible enough to let an Angular application take over and replace that UI layer with its own, which then simply dictates that the library to obey the commands it’s sent. Reporting happens whenever a public state property is updated, and the UI can use this property to update its representation of the component’s state.

obey_report_visual

One way to make this communication pattern effective is using an event emitter (some day Object.observe will be a realistic alternative), and emit events whenever our state changes. In code, we can make our library an event emitter like below. We’ll keep state in a separate private variable so that it can’t be accessed from outside of our library, making sure we’re masters of the universe when it comes to one of our instance’s state.

// always use closures, keep it to yourself
(function (window, EventEmitter2) {
  // see: http://stackoverflow.com/q/8651415/389745
  'use strict';

  // we'll keep track of state in a private variable only we can access
  var state = {};

  // we'll use this to give each instance a unique id
  var lastId = -1;

  // this is our Module's constructor
  function Module () {
    var self = this;

    // assign a new unique id
    self._id = ++lastId;

    // initialize our state with some defaults
    state[self._id] = {
      x: 0, y: 0
    };

    // invoke the EventEmitter2 constructor
    EventEmitter2.call(self, {
      wildcard: true
    });
  }

  // inherit from EE2 prototype, 'subclassing' it
  Module.prototype = Object.create(EventEmitter2.prototype);
  Module.prototype.constructor = Module;

  // expose our Module as some Thing the global object has access to.
  window.Thing = Module;
})(window, EventEmitter2);

Applying the Pattern

Applying this pattern is simply a matter of exposing commands that implementors can interact with (via our public interface), and emitting changes to our properties, while avoiding exposing these directly. We will expose commands, such as move in the example below, where users of our library can change the state of their components in a clearly defined way. They won’t be able to access this state, however, except when we choose to expose it, so they need to be paying attention to our emitted events.

// the move command
Module.prototype.move = function (x, y) {
  // get the old X and Y states, add some distance to them
  set(this, 'x', get(this, 'x') + x);
  set(this, 'y', get(this, 'y') + y);
};

// internal state setter
function set (instance, key, value) {
  state[instance._id][key] = value;

  // emit events when properties change
  instance.emit(['report', key], value);  
}

// internal state getter
function get (instance, key) {
  return state[instance._id][key];
}

Say we were using keymaster to handle keyboard input, our module could then consume input like below. Note how we don’t really even know what we’re doing, we are just telling the component:

Hey, Thing!, Obey this command, .move!

The code might look something like this:

// get a Thing instance, obviously we'll always want the same one
var component = new Thing();

var map = {
  left: -1,
  right: 1,
  up: -1,
  down: 1
};

// on left or right, move in the X axis
key('left, right', function (e, h) {
  // tell the component to move
  component.move( map[h.shortcut], 0 );
});

// on up or down, move in the Y axis
key('up, down', function (e, h) {
  // tell the component to move
  component.move( 0, map[h.shortcut] );
});

Lastly, updating our UI would also be completely decloupled from the rest of the code. Whenever the state changes, we update the position of the UI representation for our Thing instance. We don’t care how it changed, we only care that it did.

// get the element that represents our state in the UI
var element = document.getElementById('square');

// whenever we get a report on X...
component.on('report.x', function (value) {
  // update our left position
  element.style.left = value + 'px';
});

// whenever we get a report on Y...
component.on('report.y', function (value) {
  // update our top position
  element.style.top = value + 'px';
});

// initialize at X=50, Y=50
component.move(50, 50);

A Working Example

working example can be found below (be sure to click into the CodePen window before pressing the arrow keys).

Check out this Pen!

This kind of pattern might be most useful when your components present complex interactions between their different properties. In those cases, it might be even better to use Angular.js, although sometimes a combination of both might also prove to be useful. Of course, the hiding of information is entirely optional, and it might make sense not to hide anything but instead expose the properties in our components directly, however the event emitter pattern still makes sense to “report”when these events take place.

This article was originally published at http://blog.ponyfoo.com/2013/10/25/event-emitter-obey-and-report

Leave a Reply

Your email address will not be published. Required fields are marked *