Unable to understand useCapture parameter in addEventListener
Asked Answered
H

9

362

I have read article at https://developer.mozilla.org/en/DOM/element.addEventListener but unable to understand useCapture attribute. Definition there is:

If true, useCapture indicates that the user wishes to initiate capture. After initiating capture, all events of the specified type will be dispatched to the registered listener before being dispatched to any EventTargets beneath it in the DOM tree. Events which are bubbling upward through the tree will not trigger a listener designated to use capture.

In this code parent event triggers before child,so I am not able to understand its behavior.Document object has usecapture true and child div has usecapture set false and document usecapture is followed.So why document property is preferred over child.

function load() {
  document.addEventListener("click", function() {
    alert("parent event");
  }, true);

  document.getElementById("div1").addEventListener("click", function() {
    alert("child event");
  }, false);
}
<body onload="load()">
  <div id="div1">click me</div>
</body>
Heliostat answered 13/9, 2011 at 7:29 Comment(1)
Another good answer can be found here https://mcmap.net/q/55778/-why-is-39-false-39-used-after-this-simple-addeventlistener-functionFash
K
415

Events can be activated at two occasions: At the beginning ("capture"), and at the end ("bubble"). Events are executed in the order of how they're defined. Say, you define 4 event listeners:

window.addEventListener("click", function(){console.log(1)}, false);
window.addEventListener("click", function(){console.log(2)}, true);
window.addEventListener("click", function(){console.log(3)}, false);
window.addEventListener("click", function(){console.log(4)}, true);

The log messages will appear in this order:

  • 2 (defined first, using capture=true)
  • 4 (defined second using capture=true)
  • 1 (first defined event with capture=false)
  • 3 (second defined event with capture=false)
Kiblah answered 13/9, 2011 at 7:45 Comment(6)
Order of execution is not guaranteed: no specification is made as to the order in which they will receive the event with regards to the other EventListeners on the EventTarget. I haven't tested all browsers, so they may all just happen to implement it the same way. Capture events will, however, be done before non-capturing events.Remarkable
@tjameson The order of execution is guaranteed in the successor to the DOM2 spec, DOM3 events: "the implementation must determine the current target's candidate event listeners. This must be the list of all event listeners that have been registered on the current target in their order of registration."Kiblah
so this is basically got to do with event order i guessOvotestis
@slier, yes, the order in which multiple handlers for the same event are executed.Kleist
No idea why this is the accepted answer since afaik, capturing and bubbling talks about propagation behavior and not about dictating the order of execution for multiple, adjacent event handlersZumstein
Can anyone suggest a general guiding principle as to when we should use useCapture === true? It seems that in many cases it will be quite irrelevant.Teage
J
323

I find this diagram is very useful for understanding the capture/target/bubble phases: http://www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107/events.html#Events-phases

Below, content extracted from the link.

Phases

The event is dispatched following a path from the root of the tree to this target node. It can then be handled locally at the target node level or from any target's ancestors higher in the tree. The event dispatching (also called event propagation) occurs in three phases and the following order:

  1. The capture phase: the event is dispatched to the target's ancestors from the root of the tree to the direct parent of the target node.
  2. The target phase: the event is dispatched to the target node.
  3. The bubbling phase: the event is dispatched to the target's ancestors from the direct parent of the target node to the root of the tree.

graphical representation of an event dispatched in a DOM tree using the DOM event flow

The target's ancestors are determined before the initial dispatch of the event. If the target node is removed during the dispatching, or a target's ancestor is added or removed, the event propagation will always be based on the target node and the target's ancestors determined before the dispatch.

Some events may not necessarily accomplish the three phases of the DOM event flow, e.g. the event could only be defined for one or two phases. As an example, events defined in this specification will always accomplish the capture and target phases but some will not accomplish the bubbling phase ("bubbling events" versus "non-bubbling events", see also the Event.bubbles attribute).

Jacelynjacenta answered 18/5, 2012 at 14:5 Comment(5)
How about the children of the target node? When do they get the event?Milldam
Is the root of the tree actually Window, instead of document, because document is a child of Window?Marchesa
@Milldam they don't, it wouldn't make sense. The target is the inner-most element that should receive the event. If you i.e. click on <body> element (an empty place), all elements inside <body> (= all elements of page) should obviously not receive the click event.Globate
I just wish all the resources that explained the "what" included a "why". Off to more googling as usual.Kendakendal
The diagram comes from the W3C. w3.org/TR/2000/CR-DOM-Level-2-20000307/introduction.htmlTrolley
N
100

Capture Event (useCapture = true) vs Bubble Event (useCapture = false)

MDN Reference

  • Capture Event will be dispatch before Bubble Event
  • Event propagation order is
    1. Parent Capture
    2. Children Capture
    3. Target Capture and Target Bubble
      • In the order they were registered
      • When the element is the target of the event, useCapture parameter doesn't matter (Thanks @bam and @legend80s)
    4. Children Bubble
    5. Parent Bubble
  • stopPropagation() will stop the flow

use Capture flow

Demo

Result:

  1. Parent Capture

  2. Target Bubble 1

    (Because Capture and Bubble of Target will trigger in the order they were registered, so this is trigger first)

  3. Target Capture

  4. Target Bubble 2

  5. Parent Bubble

var parent = document.getElementById('parent');
var target = document.getElementById('target');

// "target" will trigger in the order of register (addEventListener()), capture / bubble don't affect the order
// #2
target.addEventListener('click', function (e) { 
console.log('Target Bubble 1');
// e.stopPropagation();
}, false);

// #3
target.addEventListener('click', function (e) { 
console.log('Target Capture');
// e.stopPropagation();
}, true);

// #4
target.addEventListener('click', function (e) { 
console.log('Target Bubble 2');
// e.stopPropagation();
}, false);

// #1 : "parent capture" first
parent.addEventListener('click', function (e) { 
console.log('Parent Capture');
// e.stopPropagation();
}, true);

// #5 : "parent bubble" last
parent.addEventListener('click', function (e) { 
console.log('Parent Bubble');
// e.stopPropagation();
}, false);
<div id="parent">
    <button id="target" style="padding: 1em 0.8em;">
        Trigger event
    </button>
</div>
Neurovascular answered 4/3, 2014 at 6:32 Comment(3)
There is a mistake in example: you declared child events in the order: 1. child capture 2. child bubble It matters! Just because if the Child will be the target of the event, listeners will be called in the same order. See the note at MDN: when the element is the target of the event 'useCapture' parameter doesn't matter. (developer.mozilla.org/en-US/docs/Web/API/EventTarget/…)Farnese
Note: For event listeners attached to the event target, the event is in the target phase, rather than the capturing and bubbling phases. Events in the target phase will trigger all listeners on an element in the order they were registered, regardless of the useCapture parameter. From developer.mozilla.org/en-US/docs/Web/API/EventTarget/…. So there exists no phase of "Children Capture" and "Children Bubble".Calque
And that explains why running the example produces "Children bubble 1" before "Children capture", when the diagram suggests that "capture" should always occur first for any element!Teage
R
25

When you say useCapture = true the Events execute top to down in the capture phase when false it does a bubble bottom to top.

Radioluminescence answered 13/9, 2011 at 7:57 Comment(0)
P
22

Summary:

The DOM spec described in:

https://www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107/events.html#Events-phases

works the following manner:

An event is dispatched following a path from the root (document) of the tree to the target node. The target node is the most deep HTML element, i.e. the event.target. The event dispatching (also called event propagation) occurs in three phases and the following order:

  1. The capture phase: the event is dispatched to the target's ancestors from the root of the tree (document) to the direct parent of the target node.
  2. The target phase: the event is dispatched to the target node. Target phase is always on the deepest html element on which the event was dispachted.
  3. The bubbling phase: the event is dispatched to the target's ancestors from the direct parent of the target node to the root of the tree.

Event bubbling, event capturing, event target

Example:

// bubbling handlers, third argument (useCapture) false (default)
document.getElementById('outerBubble').addEventListener('click', () => {
  console.log('outerBubble');
}, false)

document.getElementById('innerBubble').addEventListener('click', () => {
  console.log('innerBubble');
}, false)


// capturing handlers, third argument (useCapture)  true
document.getElementById('outerCapture').addEventListener('click', () => {
  console.log('outerCapture');
}, true)

document.getElementById('innerCapture').addEventListener('click', () => {
  console.log('innerCapture');
}, true)
div:hover{
  color: red;
  cursor: pointer;
}
<!-- event bubbling -->
<div id="outerBubble">
  <div id="innerBubble">click me to see Bubbling</div>
</div>


<!-- event capturing -->
<div id="outerCapture">
  <div id="innerCapture">click me to see Capturing</div>
</div>

The above example really illustrates the difference between event bubbling and event capturing. When adding the event listeners with addEventListener, there is a third element called useCapture. This a boolean which when set to true allows the event listener to use event capturing instead of event bubbling.

In our example when we set the useCapture argument to false we see that event bubbling takes place. First the event at the target phase is fired (logs innerBubble), and then via event bubbling the event in the parent element is fired (logs outerBubble).

When we set the useCapture argument to true we see that the event in the outer <div> is fired first. This is because the event is now fired in the capturing phase and not the bubbling phase.

Pushing answered 25/8, 2018 at 14:26 Comment(0)
F
12

It's all about event models: http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-flow You can catch event in bubbling phase or in capturing phase. Your choice.
Take a look at http://www.quirksmode.org/js/events_order.html - you'll find it very useful.

Factoring answered 13/9, 2011 at 7:34 Comment(2)
links to w3 are as or even less useful than google search i cant understand anything there.Munt
Yeah, that w3 link is just a huge bunch of words, but opposite to it, that second link to quirksmode site explains the topic very well and briefly.Haubergeon
I
12

Code example:

<div id="div1" style="background:#9595FF">
  Outer Div<br />
  <div id="div2" style="background:#FFFFFF">
    Inner Div
  </div>
</div>

Javascript code:

d1 = document.getElementById("div1");
d2 = document.getElementById("div2");

if both are set to false

d1.addEventListener('click',function(){alert("Div 1")},false);
d2.addEventListener('click',function(){alert("Div 2")},false);

Executes: Onclicking Inner Div, alerts are displayed as: Div 2 > Div 1

Here the script is executed from the inner element: Event Bubbling (useCapture has been set to false)

div 1 is set to true and div 2 set to false

d1.addEventListener('click',function(){alert("Div 1")},true);
d2.addEventListener('click',function(){alert("Div 2")},false);

Executes: Onclicking Inner Div, alerts are displayed as: Div 1 > Div 2

Here the script is executed from the ancestor / outer element: Event Capturing (useCapture has been set to true)

div 1 is set to false and div 2 set to true

d1.addEventListener('click',function(){alert("Div 1")},false);
d2.addEventListener('click',function(){alert("Div 2")},true);

Executes: Onclicking Inner Div, alerts are displayed as: Div 2 > Div 1

Here the script is executed from the inner element: Event Bubbling (useCapture has been set to false)

div 1 is set to true and div 2 set to true

d1.addEventListener('click',function(){alert("Div 1")},true);
d2.addEventListener('click',function(){alert("Div 2")},true);

Executes: Onclicking Inner Div, alerts are displayed as: Div 1 > Div 2

Here the script is executed from the ancestor / outer element: Event Capturing since useCapture has been set to true

Insole answered 6/8, 2014 at 0:9 Comment(2)
What's the meaning of the "greater than" chevrons in this context?Venusian
It is just an arrow indicating execution order, as in "Div 1 first, Div 2 second"Crouch
M
10

Given the three phases of event travel:

  1. The capture phase: the event is dispatched to the target's ancestors from the root of the tree to the direct parent of the target node.
  2. The target phase: the event is dispatched to the target node.
  3. The bubbling phase: the event is dispatched to the target's ancestors from the direct parent of the target node to the root of the tree.

useCapture indicates for which phases the event travel will be on:

If true, useCapture indicates that the user wishes to add the event listener for the capture phase only, i.e. this event listener will not be triggered during the target and bubbling phases. If false, the event listener will only be triggered during the target and bubbling phases

Source is the same as the second best answer: https://www.w3.org/TR/2003/NOTE-DOM-Level-3-Events-20031107/events.html#Events-phases

Milldam answered 12/3, 2017 at 7:8 Comment(0)
P
3

The order of definition only matters if the items are at the same level. If you reverse the order of definition in your code you will get the same results.

However, if you reverse the useCapture setting on the two event handlers, the child event handler responds before that of the parent. The reason for this is that the child event handler will now be triggered in the capture phase which is prior to the bubbling phase in which the parent event handler will be triggered.

If you set useCapture to true for both event handlers--regardless of order of definition--the parent event handler will be triggered first because it comes before the child in the capturing phase.

Conversely, if you set useCapture to false for both event handlers--again regardless of order of definition--the child event handler will be triggered first because it comes before the parent in the bubbling phase.

Purim answered 25/1, 2013 at 3:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.