Recently I was working on some frontend stuffs at my job where I had to implement a modal
open on row-click
of a datatable
. My data table structure was like this:
Under the Action column, the Buttons would trigger some fetch API calls. I had to implement a click-listener for each row, which would show the detailed information of that row on a modal
component. Everything went well. Modal was working fine. But, when I clicked on the Buttons of Action column, it triggered the fetch API call and the modal would open too.
This was an issue because no one would want to see a modal pop-up on their screen every time they clicked another action button. My brain stopped working for a moment as I could not figure out what was happening there. On further investigating the issue, I found out there is something called event propagation on the DOM tree that occurs whenever we attach some event listeners to the DOM node.
How does Event Propagation work? (Bubbling and Capturing)
Let's consider Grand parent
, parent
and child
are three HTML divs. I'll attach three listeners to the three divs.
const grand_parent = document.getElementById("grand_parent"),
parent = document.getElementById("parent"),
child = document.getElementById("child");
grand_parent.addEventListener("click", triggerClick("grand parent clicked"));
parent.addEventListener("click", triggerClick("parent clicked"));
child.addEventListener("click", triggerClick("child clicked"));
function triggerClick(data) {
console.log(data)
}
On clicking the child, we will see the following things in the console:
On clicking the parent, we will see the parent and grandparent logged-in console. Finally, on clicking grandparent, we will just see the grandparent logged.
This phenomenon is known as the Bubbling
phase of event propagation. The event bubbles up from the target element through its ancestors in the DOM tree. This is the more commonly used phase for handling events and the default behavior of any event handlers in JavaScript.
Another phase is known as Capturing
phase which does exactly the opposite of the Bubbling. During the capturing phase, the event travels from the root of the DOM tree down to the target element. This phase allows you to intercept and handle the event before it reaches its target. Capturing is less commonly used but can be helpful in certain scenarios.
The code below sets the event handlers to work in Capturing
phase.
grand_parent.addEventListener("click", triggerClick("grand parent clicked"), true);
parent.addEventListener("click", triggerClick("parent clicked"), true);
child.addEventListener("click", triggerClick("child clicked"), true);
Passing true
property will tell the event listener to work in Capturing
mode. Now, whenever we click the child. We will see the exact opposite of the previous output.
Here, when the child is clicked, first of all, the topmost parent's event handler is executed and it travels down to the target through all its ancestors. This is known as Capturing
phase of event propagation.
Stopping Event Propagation:
To fix the issue with my data table row click modal and action button click, I had to stop the propagation of the events in my action buttons. JavaScript has a method on the event object that lets us stop the event propagation on that target element.
Let's see how is it done.
grand_parent.addEventListener("click", triggerClick("grand parent clicked"));
parent.addEventListener("click", triggerClick("parent clicked"));
child.addEventListener("click", (event) => {
triggerClick("child clicked")
// stop propagation of events (bubbling / capturing)
event.stopPropagation();
});
stopPropagation()
method will tell the handler to stop executing the click handlers on the ancestors of the target element, hence, other listeners are not executed. Here, if you click the child, you will only see child clicked
in the console screen.
I set the event.stopPropagation();
on my Buttons under the action columns and now the modal component was not triggered whenever I clicked the action buttons. This was the fix for my issue with the data table row click.
Conclusion
Understanding event propagation in JavaScript is crucial for effective event handling in web development. Whether you're working with the capturing or bubbling phase, being aware of how events propagate through the DOM tree allows you to create more interactive and responsive web applications. Remember to choose the appropriate phase based on your requirements and use the stopPropagation
method wisely to control event flow.