What is the difference between event bubbling and capturing? When should one use bubbling vs capturing?
This question is related to
javascript
dom-events
event-bubbling
Bubbling
Event propagate to the upto root element is **BUBBLING**.
Capturing
Event propagate from body(root) element to eventTriggered Element is **CAPTURING**.
There's also the Event.eventPhase
property which can tell you if the event is at target or comes from somewhere else, and it is fully supported by browsers.
Expanding on the already great snippet from the accepted answer, this is the output using the eventPhase
property
var logElement = document.getElementById('log');
function log(msg) {
if (logElement.innerHTML == "<p>No logs</p>")
logElement.innerHTML = "";
logElement.innerHTML += ('<p>' + msg + '</p>');
}
function humanizeEvent(eventPhase){
switch(eventPhase){
case 1: //Event.CAPTURING_PHASE
return "Event is being propagated through the target's ancestor objects";
case 2: //Event.AT_TARGET
return "The event has arrived at the event's target";
case 3: //Event.BUBBLING_PHASE
return "The event is propagating back up through the target's ancestors in reverse order";
}
}
function capture(e) {
log('capture: ' + this.firstChild.nodeValue.trim() + "; " +
humanizeEvent(e.eventPhase));
}
function bubble(e) {
log('bubble: ' + this.firstChild.nodeValue.trim() + "; " +
humanizeEvent(e.eventPhase));
}
var divs = document.getElementsByTagName('div');
for (var i = 0; i < divs.length; i++) {
divs[i].addEventListener('click', capture, true);
divs[i].addEventListener('click', bubble, false);
}
_x000D_
p {
line-height: 0;
}
div {
display:inline-block;
padding: 5px;
background: #fff;
border: 1px solid #aaa;
cursor: pointer;
}
div:hover {
border: 1px solid #faa;
background: #fdd;
}
_x000D_
<div>1
<div>2
<div>3
<div>4
<div>5</div>
</div>
</div>
</div>
</div>
<button onclick="document.getElementById('log').innerHTML = '<p>No logs</p>';">Clear logs</button>
<section id="log"></section>
_x000D_
I have found this tutorial at javascript.info to be very clear in explaining this topic. And its 3-points summary at the end is really talking to the crucial points. I quote it here:
- Events first are captured down to deepest target, then bubble up. In IE<9 they only bubble.
- All handlers work on bubbling stage excepts
addEventListener
with last argumenttrue
, which is the only way to catch the event on capturing stage.- Bubbling/capturing can be stopped by
event.cancelBubble=true
(IE) orevent.stopPropagation()
for other browsers.
If there are two elements element 1 and element 2. Element 2 is inside element 1 and we attach an event handler with both the elements lets say onClick. Now when we click on element 2 then eventHandler for both the elements will be executed. Now here the question is in which order the event will execute. If the event attached with element 1 executes first it is called event capturing and if the event attached with element 2 executes first this is called event bubbling. As per W3C the event will start in the capturing phase until it reaches the target comes back to the element and then it starts bubbling
The capturing and bubbling states are known by the useCapture parameter of addEventListener method
eventTarget.addEventListener(type,listener,[,useCapture]);
By Default useCapture is false. It means it is in the bubbling phase.
var div1 = document.querySelector("#div1");_x000D_
var div2 = document.querySelector("#div2");_x000D_
_x000D_
div1.addEventListener("click", function (event) {_x000D_
alert("you clicked on div 1");_x000D_
}, true);_x000D_
_x000D_
div2.addEventListener("click", function (event) {_x000D_
alert("you clicked on div 2");_x000D_
}, false);
_x000D_
#div1{_x000D_
background-color:red;_x000D_
padding: 24px;_x000D_
}_x000D_
_x000D_
#div2{_x000D_
background-color:green;_x000D_
}
_x000D_
<div id="div1">_x000D_
div 1_x000D_
<div id="div2">_x000D_
div 2_x000D_
</div>_x000D_
</div>
_x000D_
Please try with changing true and false.
As other said, bubbling and capturing describe in which order some nested elements receive a given event.
I wanted to point out that for the innermost element may appear something strange. Indeed, in this case the order in which the event listeners are added does matter.
In the following example, capturing for div2
will be executed first than bubbling; while bubbling for div4
will be executed first than capturing.
function addClickListener (msg, num, type) {
document.querySelector("#div" + num)
.addEventListener("click", () => alert(msg + num), type);
}
bubble = (num) => addClickListener("bubble ", num, false);
capture = (num) => addClickListener("capture ", num, true);
// first capture then bubble
capture(1);
capture(2);
bubble(2);
bubble(1);
// try reverse order
bubble(3);
bubble(4);
capture(4);
capture(3);
_x000D_
#div1, #div2, #div3, #div4 {
border: solid 1px;
padding: 3px;
margin: 3px;
}
_x000D_
<div id="div1">
div 1
<div id="div2">
div 2
</div>
</div>
<div id="div3">
div 3
<div id="div4">
div 4
</div>
</div>
_x000D_
Description:
quirksmode.org has a nice description of this. In a nutshell (copied from quirksmode):
Event capturing
When you use event capturing
| | ---------------| |----------------- | element1 | | | | -----------| |----------- | | |element2 \ / | | | ------------------------- | | Event CAPTURING | -----------------------------------
the event handler of element1 fires first, the event handler of element2 fires last.
Event bubbling
When you use event bubbling
/ \ ---------------| |----------------- | element1 | | | | -----------| |----------- | | |element2 | | | | | ------------------------- | | Event BUBBLING | -----------------------------------
the event handler of element2 fires first, the event handler of element1 fires last.
What to use?
It depends on what you want to do. There is no better. The difference is the order of the execution of the event handlers. Most of the time it will be fine to fire event handlers in the bubbling phase but it can also be necessary to fire them earlier.
Source: Stackoverflow.com