While studying Software Engineering, one of the first things you may hear about is the Document Object Model (DOM, for short). Quickly, the DOM is an abstracted, hierarchized version of the elements in an HTML/XML document where the “root” is the document itself. From this root, other elements are “branched off” depending on how elements, attributes, and other qualities are nested in the document. Note the picture above and compare it to its equivalent in code:
When trying to introduce events and event handlers in our code, it’s important to understand where a certain event handler is in the hierarchy of elements, as well as know what event handlers are affixed to its parent elements. Let’s look at some example code that may help to explain this in detail:
Notice above that there are three elements -one nested inside the other- each with the same event handler type (“onClick”). If this were on a page and a user clicked the button element, which alert would you see: the button alert, the span alert, or the div alert?
Answer: All three, in that order! Clicking the button will prompt the button alert, then the span alert, and finally the div alert! The reason for this is event bubbling which, according to Wikipedia, is the following:
“Event bubbling is a type of event propagation where the event first triggers on the innermost target element, and then successively triggers on the ancestors (parents) of the target element in the same nesting hierarchy till it reaches the outermost DOM element or document object.”
In simpler terms, if an element and its parent have an event handler of the same type, triggering that event on the element will also trigger the parent element’s event. This will cascade up until the parent element no longer shares the same event type as its child. Event bubbling might cause some unexpected events to occur when implementing your code, because triggering one event may accidentally prompt other ancestral events to occur.
How do I stop event bubbling?
There are a few quick fixes to making sure your events don’t bubble. One way is to make sure that the parent element does not have the same event handler as its child. In our above code example, if neither <div> or the <span> elements had the “onClick” event type, clicking the <button> element would not fire off its parents’ alerts. This might not be ideal, however, when all elements have to have an identical event type.
So what to do?
Luckily, there are two very similar methods we can fire off that will stop the bubbling (or propogation of events): .stopPropagation() and .stopImmediatePropagation(). Let’s put the former in our code and see what it does:
After adding that method, the only alert we will see is the one attached to the button. In further detail, e (the event) is stopping the spread of the event trigger from moving up the chain. The buck stops there!
e.stopImmediatePropagation() does this as well, but takes this a step further: .stopImmediatePropagation() will stop all events triggered by an element from bubbling up. For example, if the elements in our code all had an additional “onClick” event, using .stopPropagation() will only stop one of those events from bubbling, but will not stop the other. stopImmediatePropagation() stops all of them.
Here, we won’t cover event capturing in too much detail, in part because it is rarely used. It is essentially the opposite of event bubbling, and is when an event propagates down from the outermost element to the target. Capturing happens each time an event is triggered, but generally does not prompt anything unless explicitly outlined in our code. The lifecycle of an event trigger can be summarized as follows:
Event Capturing => Event Targeting => Event Bubbling
EC starts the event cycle at the top-most element (say, <html>) and goes down to the target of the event (<button>). After, the target of the event propagates the event from the event target up to the outermost element (the event bubbling phase). There is even a method that will allow you to zero in on a particular part of the phase: .eventPhase(). A return value of “0”, “1”, “2”, or “3” will tell you if the event is not in any phase, the capturing phase, the target phase, or the bubbling phase, respectively.
A bubbling event may surprise you upon first encountering it. You may wonder why your event on your <div> tag is firing off when you initialize an <img> event. As discussed, you can quickly fix this by making sure parent and child elements do not share event types (such as “onClick” or “onChange”), but if that isn’t an option, pull out one of those propagation methods to stop the event at its target!
One more thing: Most events bubble, but a tiny number do not, such as “focus.”
I hope this helped you. Happy Coding!