Event bubbling concept is a way of propagating the events from the element clicked all the way to the ancestor. This is a beginner article so if you are already aware of this you can skip this article.
What is event bubbling?
The principle of event bubbling is fairly simple. Here it goes.
When an event happens on an element, the respective handler is run and is bubbled on to the parent element, the parent element handles the event and the event is bubbled on to its ancestors (except when bubbling is stopped).
event bubbling With an example
Let’s look at a sample HTML.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18<table id="grid">
<thead></thead>
<tbody>
<tr>
<td>row 1 cell 1</td>
<td>row 1 cell 2</td>
</tr>
<tr>
<td>row 2 cell 1</td>
<td>row 2 cell 2</td>
</tr>
<tr>
<td>row 3 cell 1</td>
<td>row 3 cell 2</td>
</tr>
<!-- some other tr rows -->
</tbody>
</table>
If there is an event happening on any TD
element in the above code, then the event handler for that TD
element will be fired and executed, once the TD
event handler completes its operation, then it’s parent event listener is fired (event bubbled here). So, the TR
element handles the event and passes it to the tbody
, the tbody
handles its specific thing and passes it to the table
and so on until the document object is reached.
To see this in action, let’s add event listeners for every HTML tag in the above HTML. Here’s is the demo in jsfiddle. Just try to click on any td
cell and observe that all the listeners are fired all the way up to the document listener.
The requirement for this article is that for the above table whenever we click on any TD
element we’ve to show the content in an alert (so, row x column y should be displayed).
To satisfy the requirement, we’d generally attach an event listener on the TD
element and when the user clicks we’ll alert the text in that TD
element.
1 | $(function(){ |
Now, the above code looks pretty obvious but imagine we have 100 rows and every row is having 5 columns, then the click event listener will bind to all the 500 (100 * 5) TD elements.
To solve this, we’ll just attach a listener on the grid and see if the click happened on the TD element and then take necessary action. This needs a little work, but it is just a single listener for the entire grid.
In our case, the logic should be pretty easy1
2
3
4
5
6
7$(function(){
$("#grid").on("click", function(e){
var cell= $(e.target); //Get the cell
if(cell.is('TD'))
alert('Cell data: ' + cell.text());
});
});
Well, the code works. But how does it work? Because of event bubbling. Yes, the TD element receives a click and there is no handler attached to it so bubbled up to tr, tbody these don’t have any listeners it bubbles up to the table element which has a click event handler and is fired.
Note that once the event is handled in the table (grid) it doesn’t stop there it still bubbles up to the document object (because we didn’t stop the bubbling).
Event bubbling is the concept of bubbling the events up until the hierarchy so to catch the bubbling we can have a listener on the parent element so that we can take appropriate action based on the target element. When this is implemented, we will call it as event delegation.
Javascript solution for event delegation
This is a javascript solution to event delegation. If you are using plain javascript, then you should remember one thing here. The event.target
is always the element that is clicked on and not the element it is bubbled up to.
1 | var table = document.getElementById("grid"); |
jQuery event delegation
Instead of verifying if the clicked element is TD or not, jQuery has support for event delegation. So, you can specify what element to listen on when a click happens on a grid.
definition
Event delegation allows us to attach a single event listener, to a parent element, that will fire for all descendants matching a selector, whether those descendants exist now or are added in the future.- jQuery
Here’s how we can achieve event delegation in jQuery.
1 | $(function(){ |
One might think that this is same as having the selector combined with the grid
1 | $("#grid td").on("click", function() {}); |
This is not a delegated listener because we are attaching click event listeners for all the td
elements in the #grid
. Whereas, the delegated listener will listen on the grid and if the click happens on the td
element then the listener will be fired.
Conclusion
With event delegation, we can have some performance improvements on the page.
jQuery event delegation is good but if you have to stop/off the event delegation, then the answer is you can’t! Yes, you cannot stop the event delegation on a specific element inside a parent container.
I’d recommend stopping the bubbling(using e.stopPropogation()
) if you have handled the specific event, otherwise it will fire the parent listeners if you have any.