About events

AD, please don't block.

JavaScript is what makes web pages dynamic, and interactive; one way JavaScript gives web page life is through events.

Event history in a nutshell

Netscape introduced firstly events in JavaScript at the dawn of the web; at those time people attached the event from the markup because they hadn’t other choice.

<button onclick="alert('Hello world!');">
  Click me
</button>

Slowly browsers, Netscape and IE, introduced new events, and event metadata. Their implementations were often different and not cross-browser compatible. For example, in Netscape event data were passed as parameter to the event handler:

function handler (event) {
  console.log(event.type);
}

while in Internet Explorer event data were set in the global space, as window.event.

function handler () {
  // you might be surprised to know that
  // this is still available in IE 9
  console.log(window.event.type);
}

Sometimes it was easy to find a cross-browser solution:

function handler (event) {
  event = event || window.event;
  console.log(event.type);
}

… but developers were not always that lucky.

Event propagation model

Probably the most problematic controversy concerns the events propagation model.

The events propagation model determines the execution orders of the event handlers when a certain event occurs.

Let’s consider for example the following markup, and imagine that both to the button, and the div element is registered a click event listener. The event handler logic isn’t relevant for the sake of this example.

<div id="box">
  <button id="btn">
    Click me
  </button>
</div>

What’s executed first when the button gets clicked? The event handler registered on the button, or the one registered on the div? The event propagation model answers this question.

Both Netscape, both IE developed their own event model, and as tradition the models were not compatible with each other.

In Netscape, events were handled proceeding from the parent to the childs elements; we talk in this case of event capturing.

Differently, in IE, the events propagation started from the most inner element that received the event, and proceeded by climbing the DOM tree; this is usually referred as event bubbling.

With the aim of remedying this situation, in the early years of the new millennium, W3C proposed a third model, that unifies the Netscape, and IE different approaches.

On the basis of this model, events propogate starting from the root element till the target element (capture phase) and after reaching the target, they climb up back to the root element (bubbling phase). The target element is the element that received the event.

W3C event propagation model.
W3C event propagation model.

The W3C model let web developers free - through EventTarget#addEventListener - to register an event handler for the capture phase, or the bubbling phase.

EventTarget.prototype
  .addEventListener(eventType, handler[, useCapture]);

IE only supports EventTarget#addEventListener since version 9. Older versions of IE made available attachEvent on the HTML elements; it was removed in IE11.

The third parameter is used to specify whether the event handler should be executed during the capture phase, or the bubbling phase. It’s an optional parameter, and when it’s not specified, is assumed as false, so that the event is registered for the bubbling phase.

Even more recently EventTarget#addEventListener was further extended to allow a configuration object as third parameter. You can read more about it in the mdn documentation.

On the basis of W3C model, web developers, not only plan the event handler execution order, but could also modify it while the event is still propagating through the DOM tree.

In fact the method Event#stopPropagation permits to block the event propagation through the DOM.

Let’s consider the markup from the above, and attach a couple of event handlers, one on the button, and one on its container.

document.getElementById("box")
  .addEventListener("click", () => console.log("Never executed"));

document.getElementById("btn")
  .addEventListener("click", (event) => event.stopPropagation());

In the above case the event handler attached on the button is executed first, and since it executes internally event.stopPropagation the event propagation is blocked, and the event never reach the #box element, so that its handler is never executed.

Another largely used method is Event#preventDefault.

It permits to override the browser’s default behaviour for a specific interaction (for example browser’s default behaviour when user clicks on a link is to navigate to the url to which the anchor’s href attribute points to).

document.getElementById("#fakeAnchor")
  .addEventListener("click", (event) => event.preventDefault());

Event#preventDefault has only effect for cancelable events. For example change event can’t be canceled.