Event Detection: From DTM To Launch

Recently, a question came up in the Measure Slack channel that we’ve heard far too often. Paraphrasing, it went something like this:

I’ve set up a rule in Adobe DTM that should trigger when a user clicks on a particular table cell, but DTM never seems to detect the click. Any ideas on how I can get DTM to detect the click? I noticed our app has its own click listener on the table cell and inside the handler we have event.stopPropagation().

As this user experienced, sometimes DTM has a hard time detecting when an event has occurred. Let’s see why this happens in DTM and how Launch’s event detection is more robust and solves this user’s problem in a transparent manner.

In JavaScript and the Document Object Model (DOM), events are processed in a very orderly fashion through a process called event capturing and bubbling. To understand how this process works, let’s take a simple example where we have an HTML document which contains a body, which contains a single table, which contains a single table body (tbody), which contains a single table row (tr), which contains a single table cell (td). The hierarchy looks like this:

Document Object Model (DOM)

Software developers could write JavaScript that adds one or more click event listeners to any of the elements defined in our hierarchy. Whatever the reasons may be, an app might register a click event listener on body, two click event listeners on the table, and a click event listener on the table cell, or some other variation depending on what the app is trying to do.

When an event listener is added to an element, it is either added for the “capturing phase” or the “bubbling phase”. This is very important to understand. We haven’t discussed what these phases are yet, but we will in two shakes of a lamb’s tail.

Now, let’s assume a user clicks the table cell. The event is processed through three phases, in order:

  1. Capturing phase: In this phase, all listeners registered for the capturing phase on the document are executed, then all listeners registered for the capturing phase on the body, then all listeners registered for the capturing phase on the table, then all listeners registered for the capturing phase on the table body, and then all listeners registered for the capturing phase on the table row.
  2. Target phase: In this phase, all listeners registered on the table cell are executed, regardless of whether they were registered for the capturing phase or bubbling phase.
  3. Bubbling phase: In this phase, all listeners registered for the bubbling phase on the table row are executed, then all listeners registered for the bubbling phase on the table body, then all listeners registered for the bubbling phase on the table, then all listeners registered for the bubbling phase on the body, and then all listeners registered for the bubbling phase on the document.

A picture speaks a thousand words, so they say:

DOM event phases

Limitations In DTM

Here’s the kicker. What we’ve described above is how it typically functions in “modern browsers”. Notably, Internet Explorer 8 and below do not support the capturing phase and DTM was designed to work with Internet Explorer 8 (and even earlier browsers before their support was subsequently dropped). Because of this, here’s what DTM had to work with:

DOM event phases in Internet Explorer 8 and below

In order to detect click events, DTM adds an event listener to the document:

DTM click event listener added to document for the bubbling phase

By adding a single listener to document, DTM can detect a click on any element. As DTM detects click events, it can determine which element the user clicked and whether the click is supposed to fire any DTM rules. Under normal circumstances, this works great. However…

When a click event listener is executed by the browser, it is passed an event object. Among other things, this event object has a method on it called stopPropagation(). When called, it prevents the browser from continuing to “propagate” the event, or in other words, continuing processing event handlers on subsequent elements in the capturing→target→bubbling process. In our example, the DTM user’s application had added an event listener to the table cell element and in the listener function had called event.stopPropagation(). It had the following effect:

Event propagation blocked by application

Because the application stops propagation of the event, event listeners on the table row, table body, table, body, and document are never executed. DTM never even hears about the event. As a result, rules that should have been run are not, leading to confusion and frustration for the DTM user.

As a workaround, DTM provides a checkbox that allows the user to apply the event listener directly to the element:

Checkbox for applying event listener directly to element

With this checkbox checked in our example, DTM will add an additional event listener directly to the table cell:

Additional DTM click listener applied directly to element

By doing so, DTM now has a chance to be notified about the click event even though the application’s listener prevents propagation of the event to subsequent elements in the hierarchy.

While this approach may (and did) fix this user’s particular problem, it has some notable repercussions:

  1. Additional event listeners must to be added to specific elements, leading to additional processing.
  2. DTM must continually poll the DOM, searching for newly added elements that relate to rules where this checkbox has been checked. When new elements are found, it must add an event listener to each one.

If not careful, this can be a significant hit to site performance. It’s also not very bulletproof. For example, while we’ve talked about event.stopPropagation(), there’s also event.stopImmediatePropagation(), which wreaks even more havoc for DTM.

A Better Approach With Launch

With Launch, the time had come to move forward. Support for Internet Explorer 8 was dropped and with that we now have a capturing phase to work with. Instead of being one of the last to hear about an event, Launch could now be one of the first. We now add the event listener to the document on the capturing phase:

Launch click event listener added to document for the capturing phase

With the listener in place on the capturing phase, it no longer matters if the application stops propagation of the event while the event is on the target phase. By that time, Launch will have already been notified of the event and will have run respective rules.

You’ll notice that Launch, unlike DTM, does not have an “apply event handler directly to element” checkbox. Fortunately, you should no longer need it. We hope this improved approach prevents this frustration users have encountered at times with DTM.