Michael Douglas Brett - Web Development

Hi, I'm Michael. I'm a front-end web developer based in the UK. This is my site.

Events!

FEDIQ JavaScript DOM

Mar 30th 2016

It's Front End Developer Interview Question time! This installment is brought to you in association with our good friends at left-pad.io. I've looked ahead and decided that I'm going to take this one as a twofer: 'Explain event delegation' and 'Describe event bubbling'. Why not?

But first - what are events?

The best way I can think of to describe events (specifically in relation to web development) is that they are signals, registered by the browser, that a web page has altered state or been manipulated by a user. Whether it is simply that the page has loaded, or that a user has scrolled down (or moused over an image, or clicked a button), events can be reacted to via JavaScript - and this enables a deeper interactivity and functionality in our web pages/applications.

I've already mentioned events like load and mouseover, but there are many more (you can a find a good list on MDN). In order to utilise them, you need to set up event listeners/handlers (I often see the terms used interchangeably, but if I really had to narrow it down I would say that event handlers are the code that runs on a specific event, whereas event listeners subscribe to events and call the relevant handler. But again, I see the terms used interchangeably...).

In an earlier (longer) draft of this post, I went into detail about the various methods of binding events that emerged from the Browser Wars, but for this post I'm only going to focus on the addEventListener method from the DOM Level 2 spec. I'm not saying that it isn't relevant to know about other methods of event registration, and I definitely recommend checking out PPK's articles on the 'traditional method' and the old Internet Explorer model, but my gods! - it's not a mystery why jQuery became so popular.

// Event binding...

var b = document.getElementById('exampleButton');

function handleThis(e) {
  console.log('This event was a: ' + e.type);
}

b.addEventListener('click', handleThis, false);

You can see, in the example above, that addEventListener takes:

When an event fires, an event object (e, here) is created and passed to the handler (except in old IE, unhelpfully, and again I direct you to PPK's overview - linked above).

So What About Bubbling and Delegation?

Events propagate through the DOM tree in two ways: bubbling and capture. From the spec we learn that:

Event capture is the process by which an EventListener registered on an ancestor of the event's target can intercept events of a given type before they are received by the event's target ... when an event of the given type is dispatched toward a descendant of the capturing object, the event will trigger any capturing event listeners of the appropriate type which exist in the direct line between the top of the document and the event's target.

This movement is in the opposite direction to bubbling. When bubbling...:

The event is dispatched to its target EventTarget and any event listeners found there are triggered. Bubbling events will then trigger any additional event listeners found by following the EventTarget's parent chain upward

Bubbling is the default behaviour used by the traditional method of event binding (as well as by the attachEvent() method used by the older versions of IE), but addEventListener() gives us a way to control the event flow - that final boolean, which sets the value of the useCapture parameter. Needless to say (though I'm going to), in our example:

b.addEventListener('click', handleThis, false);

... the useCapture parameter is false and the click event will bubble.

Event delegation, then, is a technique that leverages the nature of event flow - allowing us to be able to bind an event to a node potentially much higher up the DOM tree (instead of directly on multiple event targets at the same level) and allow events to naturally 'bubble up' to the listener. One listener covering many nodes leads to cleaner, less memory-intensive code.

This comes in especially handy in the case of DOM tree nodes that are being created and deleted dynamically. In David Walsh's article from 2011 he uses the example of targeting a dynamically created list of links, by placing the listener on the parent <ul> element and matching the event object's target attribute for anchor tags of a certain class.

As I alluded to earlier, event handling is so fundamental to rich web experiences that it is no wonder that popular frameworks and libraries go out of their way to make it as painless as possible.

Next time: Let's just get fizzbuzz out of the way early...