Message Systems in Programming: Part 3 of 7 – Events

Events

Events in JavaScript (and EventEmitters in Node.js) allow 1 to many; meaning 1 dude or many people can listen for the same event without the developer having to add more code to the sender.

Events also solve with finality the parameter order problem. There is only ever 1 parameter: The Event. Callbacks, Promises, and Streams can have none, or many. In dynamic languages, you have no compiler help with this. Since most Events are an object of some type, you can add as many slots as you want without changing the interface between sender and receiver. This slightly improves the ability to refactor. In strongly typed languages, the surface API doesn’t change, only the internal consumption which is often opt-in, thus helping keep OOP things OOP. w00t to the w00t. Moot point is moot.

The most common example you see is listening for a mouse click on a button in JavaScript web development, shown in TypeScript:

function clickHandler(mouseEvent:MouseEvent)
{
console.log("a mouse click:", mouseEvent);
}
myButtonOrDiv.addEventListener(MouseEvent.CLICK, clickHandler);
// or if strong-typing ain't yo thang,
// da first parameter is always a String, cha-ching!
myButtonOrDiv.addEventListener("click", clickHandler);

You setup your handler, which is a function, that runs when the event fires. In this case, when the user clicks the mouse. Sometimes it’s called an “event handler”, other times an “event callback”. Same thing.

Either way, looks like a callback, right? While they are like callbacks, all event handlers, or handlers for short, take an event as the first and only parameter. Every event that fires, whether built in ones like MouseEvents, or custom ones you make and fire yourself, has the same API.

If you want to stop listening for mouse events, you simply remove your listener:

myButtonOrDiv.removeEventListener(MouseEvent.CLICK, clickHandler);
// or without strong-typing
myButtonOrDiv.addEventListener("click", clickHandler);

If you want have many listeners, simply add it.

function clickHandler1(mouseEvent)
{
console.log("a mouse click in handler 1:", mouseEvent);
}
function clickHandler2(mouseEvent)
{
console.log("a mouse click in handler 2:", mouseEvent);
}
myButtonOrDiv.addEventListener("click", clickHandler1);
myButtonOrDiv.addEventListener("click", clickHandler2);

Notice how clickHandler2 is a completely different function. If you were to use the same function, it would NOT register an additional event.

function clickHandler1(mouseEvent)
{
console.log("a mouse click in handler 1:", mouseEvent);
}
function clickHandler2(mouseEvent)
{
console.log("a mouse click in handler 2:", mouseEvent);
}
myButtonOrDiv.addEventListener("click", clickHandler1);
myButtonOrDiv.addEventListener("click", clickHandler1);
// click on button, results in:
// a mouse click in handler 1: MouseEvent {dataTransfer: null, toElement: div#clickit, fromElement: null, y: 14, x: 45…} 

Note there are SOME Publish Subscribe libraries and API’s out there that support such functionality; i.e. multiple addListener calls to the same function pointer result in multiple event registrations, and thus you’ll need to do as many to un-register them. However, those kind of API’s put a burden on the developer to remember how many they registered, or an obtuse API to query for this number, so it’s assumed the function/object/table pointer are sufficient for a single registration since you only expect that callback to be called once per event. If another dude needs to know about it, he’ll actually be a “true other dude” vs. an additional pointer pointing to the same function.

Custom Events

The power of events in client side JavaScript is your ability to create your own and tap into the API. While many other frameworks have illustrated this concept like Backbone’s Marionette and Angular’s $broadcast and $emit, Polymer is one of the first to embrace the native JavaScript API for the actual CustomEvent part via fire and asyncFire, not to be confused with zee German’s FIIIRRREEEE!!1oneone

The idea of dispatching custom events for many potential listeners to subscribe to is common place and accepted even if the mechanisms for doing so vary between languages and platforms.

Say you’re building a component for form input and you want to dispatch event when everything is done: all inputs, all validations, and all data formatting. While you could listen for the “click” event on the Submit button, you’d still have to either manually re-trigger all the forms validations again (assuming you have a real-time time form validation here), and once complete, THEN you know it’s truly submitted. The 2 problems with that are that you’re making the consumers of the form deal with that, and that’s not very OOP encapsulated of you.

The better strategy is to create a View; a class that handles all of those concerns where they are, lets those who want to use it know: when is the form ready. Your code can do all that form validation, and then at the end, simply:

someDOMNode.dispatchEvent(new CustomEvent("formCompleted"));

And registering for it?

function onFormCompleted(event)
{
console.log("Form's complete, yo!");
}
someDOMNode.addEventListener("formCompleted", onFormCompleted);

To get multiple listeners, simply go:

someDOMNode = document.createElement('div');
function onFormCompleted(event)
{
console.log("Form's complete, yo!");
}
function onFormCompleted2(event)
{
console.log("check it, form's done mah man.");
}
var cow = {
onFizzOrm: function(e)
{
console.log("moo and stuff, form's done and stuff.");
}
};
someDOMNode.addEventListener("formCompleted", onFormCompleted);
someDOMNode.addEventListener("formCompleted", onFormCompleted2);
someDOMNode.addEventListener("formCompleted", cow.onFizzOrm);
someDOMNode.dispatchEvent(new CustomEvent('formCompleted'));
// Form's complete, yo!
// check it, form's done mah man.
// moo and stuff, form's done and stuff.

You’ll notice I passed an object’s method in the 3rd listener. Again, as long as it’s a function, she’ll work, regardless of where she’s located. #scopeLoversPizzaBeware

Wrappers

Some languages provide Event dispatching as a core mechanism that can be optionally added to DisplayObject tree’s. Sadly ECMAScript requires Document Object Model (called DOM for short) elements. This means you cannot use Event dispatch capabilities in your data layer (code that has nothing to do with View’s, HTML, CSS, div’s, etc). This is often why many frameworks tend to eschew Events for View level concerns, and use their own pub sub library for Controller and Model level concerns. It’s also funny to see Polymer do it like Flex did where you have an http call co-chilling next to a bar chart and they be all like, “Sup dawwwwg, I’m bound to you, and you to me, and we’re separated by just 1 line break… small world, right!?”

Backbone assumes you’ll use JQuery for DOM level concerns and Events, but will use Backbone.Events as a way for Views and Models to talk to each other. Angular actually embraces this DOM lover scenario with emit and broadcast. Polymer embraces the basic event structure of CustomEvents with a wrapper method called fire. Node’s got EventEmitters, but has no event bubbling capabilities ’cause there ain’t no DOM on the server in the API code.

Event Bubbling

If you’ve ever built composite GUI’s, i.e. components that contain components, then you’ll understand the concept of event bubbling pretty quickly. For those familiar with Angular, it’s similar to $scope.$emit.

Considering a UI is built from clickable parts that can contain other clickable parts, no longer is it as simple as “I clicked on this thing here”. When you stack 20 things on top of each other, which one did you really click on? You’d think the one on top, but EACH thing gets its own click event. To be clear, “things” in the HTML world is div, or more specifically Node (not Node.js) and EventTarget mashed together. While people traditionally think of buttons and other controls as the things you click on, nowadays not so much.

Many controls are not easily skinnable, are missing functionality, or work differently across different browsers vs. mobile. Some are even made of ShadowDOM parts. For these reasons divs are often what you click on. These divs can also contain other divs which are effectively components/buttons/controls in their own right.



Click Me

Sometimes you just want to know “the user clicked on the Submit button in the form”; whether it’s an actual <button>, a div you’ve decorated, or a series of things inside a ShadowDOM custom web component. Other times you want to know “the user clicked on the form itself”. While still other times you want to know “the user clicked on item 39 of that long list buried deep in the dom sea” or in your custom draggable window “the user clicked on the header bar, not the window contents, thus I should start dragging the window”. That last one is a capture phase, when bubbling goes the opposite way, like tears in the rain.

In my Flash and Flex experience, the use cases for actually using event bubbling are rare. The only ones I’ve used consistently are for lists, when creating draggable containers such as video game UI’s or emulating a windows based interface, or for Supervising Controller frameworks.

Bubbling up items in some form of list or datagrid control so I can write the click event handler in 1 place instead of adding for each item. If I have 100 listen items, I don’t want to add 100 click handlers. Instead, you add 1, and any click that happens within the list is bubbled up to you. The same technique is used for tile based games such as a tower defense or point and click to walk to tile game. You don’t want a click handler for each tile in a hundred to thousand tile grid; you just want 1 and you use the X and Y values to do the math on what tile you clicked on.

For example, lets say you’ve created a dynamic list and want to know what piece of data the user clicked on.

You have to correlate the index number of the list item and use it to access the data in the Array. Now, in a simple world you could do so like this using the event’s target property to identify which of the list items was clicked on:

<ol id="myList"></ol>
<script>
data = ["Uno", "Dos", "Tres"]; 
list = document.getElementById('myList');
function itemClicked(item)
{
console.log("you clicked on item:", item);
}
data.forEach(function(item)
{
var listItem = document.createElement("li");
listItem.innerHTML = item;
list.appendChild(listItem);
list.addEventListener("click", function(event)
{
itemClicked(item);
console.log(event);
event.stopImmediatePropagation();
});
});
</script></pre>

You’ll notice on line 17, we create a new anonymous function for each list item. Since it’s created in that context, it retains a unique link to the item that was used to create it. This is nice; whenever it’s clicked on, we know which item it represents, and call itemClicked with it.

The bad? Really dude? A listener for EACH list item? What if you have a hundred or more list items, or the list redraws often? You’ll end up with a ton of listeners, many of which you’ll then later throw away. Dat shiz cray. You’ll make the Garbage Collector work overtime, and potentially get jank on your animations. Also notice we’re turning event bubbling OFF on line 21. I’ll explain that in a bit.

Let’s show how you make event bubbling work for you vs. against you:

data = ["Uno", "Dos", "Tres"]; 
list = document.getElementById('myList');
function onItemClicked(event)
{
console.log("you clicked on: " + event.target.getAttribute("data-item"));
}
list.addEventListener("click", onItemClicked);
data.forEach(function(item)
{
var listItem = document.createElement("li");
listItem.setAttribute("data-item", item);
listItem.innerHTML = item;
list.appendChild(listItem);
});

The same technique goes for any DisplayObject based framework where you use many different vector shapes, bitmaps, or whatever to composite together to form an interface. It isn’t always flat.

Not all events bubble by default, but MouseEvents do.

The above is just 1 level deep, but the rabbit hole goes much deeper. The 2nd, less used use case is when you have some sort of View, whether a Backbone or Ember child View, or even an Angular Controller. Much like the List example above, these are actual Views. They could just be a List item with some slightly extended functionality, or perhaps they’re complex Web Components using mad amounts of composition of other Views within them. Higher level Views are delegated with the responsibility of handling application level events such as navigating to other places in the View, basically things that deal with user interactions that don’t affect data.

In Backbone/Ember’s case, you simply dispatch your own events, except you ensure bubbling is true. They’ll wind their way up the DOM so those higher level Views can hear those events. This has the side benefit of not caring if you refactor your Views later because no matter where those child Views are, their message will be received.

// some random child View
dispatchEvent("userClickedOnShowInventory", true);

Note the 2nd parameter; it’s false by default.

Stopping Event Bubbling

You can stop events from bubbling up further by either stopPropagation or stopImmediatePropagation.

These are hard to remember the difference, so here’s a definition of both written by an art major vs. a computer scientist.

Think of stopPropagation as “stop bubbling” and stopImmediatePropagation as “stop everything”. The word “immediate” should help you remember “omg, stop all the bubbling things!”.

The stopPropagation method will stop all event bubbling to any parents of the current element, but if other people have click events registered at your level, they’ll get their event handlers run in the same call stack. The stopImmediatePropgation stops everything after your handler is done executing.

Showing the modified example above, we’ve nested our list in 2 additional container divs, and added additional click handlers to them to see bubbling in action, and see what happens when we stop it. Observe:

<div id='appUpInThisMug'>
<div id='datContainerThough'>
<ol id="myList"></ol>
</div>
</div>

And our updated code:

data = ["Uno", "Dos", "Tres"]; 
list = document.getElementById('myList');
function onItemClicked(event)
{
console.log("you clicked on: " + event.target.getAttribute("data-item"));
}
list.addEventListener("click", onItemClicked);
data.forEach(function(item)
{
var listItem = document.createElement("li");
listItem.setAttribute("data-item", item);
listItem.innerHTML = item;
list.appendChild(listItem);
});
function onContainerClicked1(event)
{
console.log("onContainerClicked1");
}
function onContainerClicked2(event)
{
console.log("onContainerClicked2");
}
var container = document.getElementById('datContainerThough');
container.addEventListener("click", onContainerClicked1);
container.addEventListener("click", onContainerClicked2);
var app = document.getElementById('appUpInThisMug');
app.addEventListener('click', function(event)
{
console.log("app clicked 1");	
});

When you click any in the list, you get:

you clicked on: Uno
onContainerClicked1
onContainerClicked2
app clicked 1

Cool, the list item gets his click first, it then bubbles up to the 2 container listeners, and finally to the top at app.

Let’s just stop all bubbling when it gets to the container:

function onContainerClicked1(event)
{
console.log("onContainerClicked1");
event.stopPropagation();
}

We now get:

you clicked on: Uno
onContainerClicked1
onContainerClicked

Notice the 2nd container still gets to run, but bubbling beyond that level has been stopped.

If we swap out stopImmediatePropagation:

function onContainerClicked1(event)
{
console.log("onContainerClicked1");
event.stopImmediatePropagation();
}

You see only the 1st bubbled event is fired, but his sibling and his parent are not:

you clicked on: Uno
onContainerClicked1

You use stopImmediatePropagation if you want to ensure a bubbled event you know is up there somewhere isn’t fired. This can happen in games. It can also be useful when creating deeply nested Views and you’re manually propagating your own custom events that have more meaning than “click”.

I have no idea why you’d ever use stopPropagation.

Event Cancelling

Another feature of events typically used mostly in UI operations is event cancelling. It’s sometimes used conjunction with event bubbling, but the more common use case is for stopping functionality from happening you don’t want to happen, thus a supported way of opt-ing out.

For example, by default an anchor tag will navigate the browser to whatever URL you’ve put in the href attribute. You can simply stop this behavior by calling preventDefault. This is different in event bubbling in that even if the event bubbles up, whatever native behavior the browser is supposed to do, it now won’t.

Event Pros

You use events when you want to have multiple people hear abeout the same change. Callbacks are 1 to 1, whereas Events are 1 to many.

Events provide flexibility to emitting many different changes from a single object. For example, we can emit both MouseEvents, KeyboardEvents, and FocuseEvents all from the same Button. You can even give fine grain context about the event, such as a mouse up event vs. a mouse down event, or which key was pressed in the keyboard down event. Callbacks can do this as well, but again, only 1 object can hear about it.

Most events we care about in JavaScript web development support this format, as do Flash & Flex, Corona SDK using Lua, and many others. It’s a common way of doing 1 to many message systems.

As you can already see, events prevent the parameter order problem; events are objects so order doesn’t matter.

You’ll notice that the event names are strings. This means you can create your own events with any name you want as long as it doesn’t conflict with built in ones such as “click”, “onfocus”, etc. This makes them flexible and easy to work with, even in strongly-typed languages.

For GUI systems, if you’re dealing with a bunch of lists or nested Views that handle application level events ONLY related to UI concerns, the bubbling can come in handy by reducing how many event listeners you need to create. This also makes handling View level concerns easier through Composition vs. letting a framework deal with it.

For asynchronous operations, finite state machines, or operations that take some random amount of time and may not succeed, events are perfect.

Event Cons

You can’t object pool them in most frameworks. If you are dispatching many different events, each one is a unique object created, usually with an assumed limited lifetime, which has a performance impact both in creation as well as in garbage collection. It’s not noticeable in applications, more so in games.

Events on the client have also fallen out of fashion long ago for a variety of reasons. Yes, we have things “in fashion” in programming. It doesn’t mean those out of fashion are bad, it’s just harder to start a conversation with some people when you talk about the “boring” things.

First reason is JQuery’s rise to fame and it improving upon the events API via it’s own callbacks, not to be confused with the callbacks I’ve described at the top of this article. Keep in mind everything I described too is not the same cross browser. Different versions of IE, older versions of Firefox, etc. are all different. JQuery helped make all of that sane to work with, and developed it’s own conventions.

Events are very div specific whereas JQuery encourages you (vs. make you) think more in selectors, classes, and ID’s. Simple features help the sale, too, like an option to have an event only fire once. The syntax is a lot smaller too.

Second reason is pub sub messaging frameworks started popping up in JavaScript that helped provide a tighter syntax, better cross browser support, and worked in both UI and non-UI code. Basically globally; anywhere in your code. Most pub sub libraries could receive a message regardless if they were defined in UI code or application framework code. Events on the other hand don’t, they get cloned if you manually re-dispatch, and bubbling is strictly tied to the DOM tree. This is why Node.js developed their own EventEmitter.

Third reason is that JQuery helped continue to fuel the Functional Programming momentum that Python and Ruby on Rails helped popularize. This eventually matured to Reactive Programming which cemented things like Promises, Deferred, Observers, and Event Streams into standard (read: “cool and new and I must use it everywhere”) ways of doing GUI programming on the web. Kind of like how wearing Axe body spray makes you cool even if you weren’t before. Yeah.

Examples often cited include “callback hell” where dealing with multiple callbacks from asynchronous events results in a ton of “event registrations up top, handler soup at the bottom”. Worse is when you start nesting these callbacks like out of control if/then statements, and it’s basically hard to read and debug. Utilizing functional programming patterns makes the code easier to read and easier to debug.

Events have this awkward place in Reactive Programming, at least for the front-end, in that they are now merely a potential delivery message, and no longer the way to register and dispatch messages, thus keeping single parameter/result advantage that events have. Languages like Dart still support using both, but discourage their use indirectly by espousing their nice Reactive Programming implementation via Futures (Promises) and Streams.

Those using Streams intentionally avoid the 1 to many support Events have by continually merging streams of complex systems to funnel all events into 1 pipeline, leaving it to the consumer to filter out the events they want. On top of a View layer, this can work fine, but not within a View layer where events still reign supreme.

They aren’t going away in that all browsers support the basic ones for mouse events, touch events, keyboard events, focus, and form events to name a few. Most code nowadays, however, abstracts them away into a less verbose API.

They also survive in other languages that allowed a flattening of UI tree, such as Flash’s EventDispatcher and Corona’s EventListener (which has View and Global versions). This, flattening the UI vs. using event bubbling, is especially important when you bring in OpenGL/3D functionality because you want as little composition as possible, so things like event bubbling constitute a code smell.

<< Part 2 – Callbacks | Part 4 – Publish Subscribe >>