Event Bubbling is essentially a means to stack events. The term bubbling derives from the fact that the stacked events would "bubble" up from the inside out.
Let's explain. If we had a <button>, and it was nested inside of a paragraph <p>, and it in turn was nested inside of a <section>. The code would look something like this:
<section>
<p>
I am a paragraph.
<button>Click Me</button>>
</p>
</section>
The button is nested inside of a <p> element, which is nested inside of a <section> element.
Now let's ad an inline click event to each of these HTML elements. *Reminder: it is generally considered "NOT good programming" to use inline events. We only use them here to demonstrate the concept.
And now when you "click" the button you will see the bubbling effect of cascading, or nested events. You will actually get all three alerts stacked on top of each other. When you click "OK" on the top alert, then next one will show, and so on.
I am a paragraph.
stopPropagation()
It's not very common to use a bubbling effect, but if you did, you might want to stop the bubbling process before it bubbles to the top. Fortunately, JavaScript gives you a way to accomplish this.
Let's start with a <button> nested inside of a <div>:
<div id="divContain">
This is my <div> element
<button id="divButton">Click Me</button>
It has some text in it
</div>
Notice that we have given both the <div> and the <button>, id's to separate them from the previous button on the page, and also for independent processing in the JavaScript.
Now, let's say we want to change the background color of the <div> when we click on the <button>. This is simple with the following JavaScript:
*colorPick(); is a previously used function that we wrote to pick a random HEX color in our Random Color Picker project, found here.
And with this code, we would get:
This is my <div> element
It has some text in it
And now, every time we click on the <button>, we get a new random background color for the <div> container. As you can see in the code, this was accomplished by adding a click event to the <button> element, which affects the color change to the <div> container.
But, what if we also want to add a separate click event to the parent <div> element, while maintaining our previously added random color click event? And in this new click event, we want to actually hide the parent <div> element?
Our JavaScript would look like:
// same code from above
divButton.addEventListener('click', function() {
divContain.style.backgroundColor = colorPick();
})
// newly added code to hide Parent Container <div>
divContain.addEventListener('click', function() {
divContain.style.display = 'none';
})
This is my <div> element
It has some text in it
And when you click the <button> it hides the parent <div> element. But what about the background color change? It should have changed the background color for the Parent <div>, before it hid it. But did it actually do that? Everything happened so fast, kinda hard to tell :/ Actually, the only way to tell is by looking in the Page Inspector, finding the Parent <div> and seeing if it has a background color assigned as an inline style.
And when we look, we see that it did in fact, change the background color.
*note: once an element's display property is set to none, it is gone from for the webpage, so there is nothing to click on to return it to display. There are some coding workarounds for this but they are beyond the scope of this discussion. For now, simply refresh the page to bring everything back.
And now, here is the point of using stopPropagation()
In this instance, even though we have created a bubbling effect by nesting (what becomes our events) in the HTML markup, we do NOT want the bubbling to propagate beyond the first event, which was to change the background color of the Parent <div> element.
So after we process the first event and change the background color, we cancel the "bubbling" with the following code:
// newly added code to stop the event "bubbling" propagation
evt.stopPropagation();
})
divContain.addEventListener('click', function() {
divContain.style.display = 'none';
})
*Notice that we are using the object event, evt, to stop propagation of the divButton event. So once this event fires and changes the Parent <div> element's background color, the "bubbling" propagation ends and there are no further events firing.
This is my <div> element
It has some text in it
One last thing to understand is that the "hide" event on the Parent <div> element, is still an active event. If we click "off" of the <button>, and click on the Parent <div> element, it will still hide the <div> element. The reason for this is that, the only thing we stopped propagation on are the "nested events" bubbling up through the "nested" <button> event. Remember, the nested "bubbling" events are:
the divButton event is nested inside
the divContain event, through the HTML Markup
If you click on the Parent <div> it only runs the divContain event, which hides the <div>. But if you click on the <button>, it fires the divButton event, and then "bubbles up" and fires the divContain event. And this propagation, or "bubbling up" is what stopPropagation() is stopping.