Real world example where event capturing is necessary / preferred?

The addEventListener DOM method supports a third optional, boolean parameter (useCapture) to indicate whether the function should use event bubbling or event capturing as propagation method. In this article the difference is nicely shown (click on the examples & view code).

From other questions on SO and blog posts, I concluded event bubbling was preferred mostly because IE8- didn't support it.

Suppose I'm only required to support IE9+, in what situation would event capturing be necessary or preferred over event bubbling? In other words, in what situation would it be better to let the events execute on the outermost elements first, and then the innermost elements? I'm looking for a simple, real world example to demonstrate the use of event capturing...

Answers:

Answer

Event capturing used to be the only option outside of the Internet Explorer browser:

One of the major differences of the back then two important browsers was how they handled events. Microsoft worked with the bubbling phase - meaning the event first passes the parent elements and then runs down to the target element. Netscape did it the exact other way - and had the event first hit on the target element and then traverse the whole DOM upwards hitting on the parent nodes - capturing. This caused developers in the early days a lot of trouble and the W3C finally specified an approach where both kind of works and can be used at free will.

Event capturing is useful in event delegation when bubbling is not supported. For example:

Some events, such as focus, don't bubble but can be captured. The inline handler on the target element triggers before capture handlers for the target element.

Many newly specified events in the web platform (such as the media events) do not bubble, which is a problem for frameworks like Ember that rely on event delegation. However, the capture API, which was added in IE9, is invoked properly for all events, and does not require a normalization layer. Not only would supporting the capture API allow us to drop the jQuery dependency, but it would allow us to properly handle these non-bubbling events. This would allow you to use events like playing in your components without having to manually set up event listeners.

Custom events and bubbling have the following issues:

Currently, Ember relies on jQuery for event handling, doing so comes with several costs:

jQuery silently changes inline handlers to bubble handlers.
    This changes expected invocation order
    This can cause automated tests to fail
Events triggered via jQuery.trigger trigger handlers in a different order than events triggered by a user.
    This changes expected invocation order
    This leads to difficult to reason about and debug aberrations in behavior
    This often causes automated tests to fail
Events must flow down and bubble back up through the entire DOM before being detected by the Ember application, and then must undergo an expensive delegation process that is effectively re-bubbling to find the right handler.
Handlers attached directly within components or by non-ember plugins take precedent over handlers attached by Ember, whether this was desired or not.

    This causes component handlers to have far-reaching side-effects
    This leads to difficult to reason about and debug aberrations in behavior
    This often causes automated tests to fail

A media player focus=>play preprocess/postprocess event flow would be a simple use case.

The mechanics of the capturing phase make it ideal for preparing or preventing behavior that will later be applied by event delegation during the bubbling phase. And that’s how we’re going to use it here—to initialize the sortable in response to a mouse click, but just before the event starts bubbling and other handlers have a chance to deal with it.

To make use of capturing, we have to go down to the metal. jQuery’s event methods only work for bubbling and don’t let us tap into the capturing phase. The capturing handler looks like:

    document.addEventListener("mousedown", function(event) {
      if ($(event.target).closest(".sortable_handle").length) {
         $("article.todolist, section.todolists").sortable();
         }
      }, true);

References

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.