What is the difference between event event bubbling and capturing?
Which of the two is the most indicated to use? In which aspects is each of them more efficient? In which cases would we use each of them?
What is the difference between event event bubbling and capturing?
Which of the two is the most indicated to use? In which aspects is each of them more efficient? In which cases would we use each of them?
Bubbling means an event that propagates from the element that
I execute the event ( event.target
), to the farthest element in the hierarchy that has the same event. In other words, from the source of the event to the farthest ancestor:
form, div, p{
border:solid red 1px;
padding:2px;
}
<form onclick="alert('form')">FORM
<div onclick="alert('div')">DIV
<p onclick="alert('p')">P</p>
</div>
</form>
Notice how the event p
is first executed, then div
and finally form
. That is bubbling.
To stop the bubbling the event#stopPropagation()
method is used:
function formFn()
{
alert('form');
}
function divFn()
{
alert('div');
}
function pFn(e)
{
alert('p');
e.stopPropagation();
}
form, div, p{
border:solid 1px red;
padding:10px;
}
<form onclick="formFn()">FORM
<div onclick="divFn()">DIV
<p onclick="pFn(event)">P</p>
</div>
</form>
As for capturing it is the opposite of bubbling: that instead of executing the events from the source to the ancestor, it would be from the ancestor to the source.
For example, look at how 2 events are defined here, 1 for the form
and another for the p
. Note that when you click on the p
element, the event of form
is executed and then it goes to p
, while if you click on form
, only its event is executed:
var usarCapture = true;
document.querySelector("#form")
.addEventListener("click", function(e){
alert("clic sobre form");
}, usarCapture);
document.querySelector("p")
.addEventListener("click", function(e){
alert("clic sobre p");
}, !usarCapture);
form, div, p{
padding:10px;
border:solid 1px red;
}
<form id="form">FORM
<div>DIV
<p>P</p>
</div>
</form>
As you may have already noticed, bubbling is the default event. If you want to use capturing, you would only have to pass true
as the last parameter to the addEventListener
method.
Regarding the cases of uses, it is always recommended to use bubbling because it is the easiest way to discover the position of the element that launched the event. I have never seen the need to use capturing and you will surely have your reasons that by default it is bubbling.
In JavaScript when an event is executed in an element of the DOM, there are 3 different phases which are executed in the following order:
Let's see an example of bubbling, if we have a hierarchy of elements which capture the same type of event, these will be activated from the objective element to the father:
body * {
margin: 10px;
border: 1px solid red;
text-align: center;
}
<form onclick="alert('Evento form')">Form
<div onclick="alert('Evento Div')">Div
<p onclick="alert('Evento objetivo')">Objetivo
</p>
</div>
</form>
As you can see, if we click on the objective element, the alert of this one is activated, later of the Div and at the end in the Form, this is bubbling, from the target to the father.
Now we go with capturing, which is in the opposite direction and we can see it running using the function addEventListener(evento, manejador[, capturing])
on an element, let's see an example:
document.getElementById('form').addEventListener("click", e => alert('Capturing en form'), true)
document.getElementById('form').addEventListener("click", e => alert('Bubbling en form'))
document.getElementById('div').addEventListener("click", e => alert('Capturing en div'), true)
document.getElementById('div').addEventListener("click", e => alert('Bubbling en div'))
document.getElementById('objetivo').addEventListener("click", e => alert('Capturing en el objetivo'), true)
document.getElementById('objetivo').addEventListener("click", e => alert('Bubbling en el objetivo'))
body * {
margin: 10px;
border: 1px solid red;
text-align: center;
}
<form id='form'>Form
<div id='div'>Div
<p id='objetivo'>Objetivo</p>
</div>
</form>
In this second example, we added an alert to the capturing events, placing a true as third parameter in addEventListener, and we can see the order in which they are executed. the events, first the capturing, from the father to the objective element and then back the bubble, from the target to the father.
All this has many advantages depending on what you want to achieve in your code, capturing is not very used by its nature to be from the parent node to the child node, however bubbling is very important and we must take into account the time to use events in JavaScript, as propagating to the document
element can cause something we do not want.
I leave this excellent post by Javascript.info , is in English but explains in a more detailed way the propagation of events, how to stop it and the properties that we must know about each event.
Difference between capture and bubbling
bubbling runs through the sun tree from the depths outwards
capture is the opposite of bubbling
Example for bubbling
window.onload = function() {
var c = document.getElementById("c");
var a = document.getElementById("a");
var b = document.getElementById("b");
c.addEventListener("click", f1, true);
b.addEventListener("click", f2, true);
a.addEventListener("click", f3, true);
}
function f1() {
console.log("has pulsado en el boton C");
}
function f2() {
console.log("has pulsado en la B")
}
function f3() {
console.log("has pulsado en la A")
}
<div id="a">
<div id="b">
<p><input type="button" id="c" value="a"></p>
</div>
</div>
example to capture
window.onload = function() {
var c = document.getElementById("c");
var a = document.getElementById("a");
var b = document.getElementById("b");
c.addEventListener("click", f1);
b.addEventListener("click", f2);
a.addEventListener("click", f3);
}
function f1() {
console.log("has pulsado en el boton C");
}
function f2() {
console.log("has pulsado en la B")
}
function f3() {
console.log("has pulsado en la A")
}
<div id="a">
<div id="b">
<p><input type="button" id="c" value="a"></p>
</div>
</div>