Hello Developers!! In this part of the series, we'll discuss the Event Propagation in detail.
The standard DOM Events describes 3 phases of event propagation:
- Capturing phase – the event goes down to the element.
- Target phase – the event reached the target element.
- Bubbling phase – the event bubbles up from the element.
Event bubbling and capturing are two ways of propagating events that occur in an element that is nested within another element when both elements have registered a handle for that event.
In this article we'll cover the following concepts in detail:
- Event Bubbling
- Event Capturing
- Stop Propagation
- Once method
Setup
To understand these concepts more clearly first we'll create nested HTML Elements and attach an event listener to them.
index.html file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="grandParent">
<h2>grandParent</h2>
<div class="parent">
<h2>parent</h2>
<div class="child">
<h2>child</h2>
</div>
</div>
</div>
<script src="index.js"></script>
</body>
</html>
index.js file:
const divs = document.querySelectorAll('div');
function logText(e) {
console.log(this.classList.value);
}
divs.forEach(div => div.addEventListener('click', logText, {
capture: false,
}));
In the above code snippet, we have created 3 divs and attach a click event listener on each of them.
addEventListener() sets up a function that will be called whenever the specified event is delivered to the target.
Syntax: target.addEventListener(type, listener [, useCapture]);
- type: A case-sensitive string representing the event type to listen for.
- listener: The object that receives a notification (an object that implements the Event interface) when an event of the specified type occurs.
- useCapture (Optional): A Boolean indicating whether events of this type will be dispatched to the registered listener before being dispatched to any EventTarget beneath it in the DOM tree.
If not specified, useCapture defaults to false. i.e. by default Event Bubbling is enabled.
Event Bubbling
When an event happens on an element, it first runs the handlers on it, then on its parent, then all the way up on other ancestors.
In the case of Event bubbling, if you click on child div then it moves up to the hierarchy and goes directly to the start of the DOM.
Events that are bubbling upward through the tree will not trigger a listener designated to use capture.
const divs = document.querySelectorAll('div');
function logText(e) {
console.log(this.classList.value);
}
divs.forEach(div => div.addEventListener('click', logText, {
capture: false, //set Event Capturing to false
}));
As shown in the above example, if we click the child div then the event is triggered and it is first handled by the innermost element and then propagated to the outer divs.
Event Capturing
Event capturing is the event that starts from the top element to the target element.
In the case of Event Capturing, the event is captured from upward up to down the DOM tree.
Event Capturing is also known as Event Trickling.
const divs = document.querySelectorAll('div');
function logText(e) {
console.log(this.classList.value);
}
divs.forEach(div => div.addEventListener('click', logText, {
capture: true, //set Event Capturing to true
}));
As shown in the above example, whenever you click the child div, the event is first captured by the top element and move down to the target element (an element that triggered the event).
Stop Propagation
The stopPropagation() method of the Event interface prevents further propagation of the current event in the capturing and bubbling phases.
const divs = document.querySelectorAll('div');
function logText(e) {
console.log(this.classList.value);
e.stopPropagation(); // stop further bubbling and capturing
}
divs.forEach(div => div.addEventListener('click', logText, {
capture: true, //set Event Capturing to true
}));
If you add e.stopPropagation();
then it prevents the event propagation. Let's understand this using an example:
As you noticed in the above example, when we click on the child div, first the event is captured by grandParent div, and output is printed to the console but as soon as it encounters e.stopPropagation()
it stops further propagation and does not move down to the target element.
Once method
A Boolean indicating that the listener should be invoked at most once after being added. If true, the listener would be automatically removed when invoked.
const divs = document.querySelectorAll('div');
function logText(e) {
console.log(this.classList.value);
}
divs.forEach(div => div.addEventListener('click', logText, {
capture: true,
once: true // Listener is invoked atmost once
}));
If we set once: true
then the event listener is invoked only once and after that, it is removed automatically.
Wrap Up!!
Thank you for your time!! Let's connect to learn and grow together.