Bubbling and Capturing - Events
Browser Events: Bubbling / Capturing
Can you explain event bubbling in JavaScript?
View Answer:
HTML:
<div id="outer">
<div id="inner">
<button id="button">Click me!</button>
</div>
</div>
JavaScript:
// Event listener for the outer div
document.getElementById("outer").addEventListener("click", function() {
console.log("Outer div clicked");
});
// Event listener for the inner div
document.getElementById("inner").addEventListener("click", function() {
console.log("Inner div clicked");
});
// Event listener for the button
document.getElementById("button").addEventListener("click", function() {
console.log("Button clicked");
});
In this example, when you click the button, the event will propagate upwards through the nested elements. So, when you click the button, the console will display the following output:
Output:
Button clicked
Inner div clicked
Outer div clicked
This demonstrates the event bubbling behavior, where the event is triggered on the innermost element and then propagates up through its parent elements.
What is event capturing in JavaScript?
View Answer:
HTML:
<div id="outer">
<div id="inner">
<button id="button">Click me!</button>
</div>
</div>
JavaScript:
// Event listener for the outer div with event capturing
document.getElementById("outer").addEventListener("click", function() {
console.log("Outer div clicked (capturing)");
}, true);
// Event listener for the inner div with event capturing
document.getElementById("inner").addEventListener("click", function() {
console.log("Inner div clicked (capturing)");
}, true);
// Event listener for the button with event capturing
document.getElementById("button").addEventListener("click", function() {
console.log("Button clicked (capturing)");
}, true);
In this example, when you click the button, the event will be captured in the capturing phase and propagate downwards through the nested elements. So, when you click the button, the console will display the following output:
Output:
Outer div clicked (capturing)
Inner div clicked (capturing)
Button clicked (capturing)
This demonstrates the event capturing behavior, where the event is triggered on the outermost element and then propagates down through its child elements.
What is the bubble-up principle concerning events?
View Answer:
<style>
body * {
margin: 10px;
border: 1px solid blue;
}
</style>
<!-- this will return the p, div and form alerts -->
<form onclick="alert('form')">
FORM
<div onclick="alert('div')">
DIV
<p onclick="alert('p')">P</p>
</div>
</form>
Can you explain what the event target is in JavaScript?
View Answer:
HTML:
<button id="myButton">Click me!</button>
JavaScript:
document.getElementById("myButton").addEventListener("click", function(event) {
console.log("Event target:", event.target);
});
In this example, we have a button with the id "myButton". When you click the button, the event listener function will be triggered, and it will log the event target to the console.
For instance, if you click on the button, the console output will be:
Event target: <button id="myButton">Click me!</button>
The event.target
property gives you access to the actual element that triggered the event, in this case, the button element with the id "myButton".
The current target is the precise target at which the current action takes place, where "this = event.currentTarget." It is conceivable that event.target equals either this or the current target.
How can you prevent the default action using JavaScript?
View Answer:
HTML:
<a href="https://www.example.com" id="myLink">Click me!</a>
JavaScript:
document.getElementById("myLink").addEventListener("click", function(event) {
event.preventDefault(); // Prevents the default action (navigating to the URL)
console.log("Default action prevented");
});
Can you capture and bubble events at the same time?
View Answer:
HTML:
<div id="myElement">
<button id="myButton">Click me!</button>
</div>
JavaScript:
document.getElementById("myElement").addEventListener("click", function(event) {
console.log("Event captured: (capturing phase)");
}, true);
document.getElementById("myElement").addEventListener("click", function(event) {
console.log("Event bubbled: (bubbling phase)");
}, false);
Output:
Event captured: (capturing phase)
Event bubbled: (bubbling phase)
What is the purpose of the third argument in the "addEventListener" method?
View Answer:
Here's an example that demonstrates the use of the third argument, useCapture
, in the addEventListener
method.
<div id="outer">
<div id="inner">
Click me
</div>
</div>
<script>
function handleClick(event) {
console.log("Target element: " + event.target.id);
console.log("Current target element: " + event.currentTarget.id);
}
var outerElement = document.getElementById("outer");
var innerElement = document.getElementById("inner");
// Attaching event listeners with different useCapture values
outerElement.addEventListener("click", handleClick, false); // Bubbling phase
innerElement.addEventListener("click", handleClick, true); // Capturing phase
</script>
In this example, we have an outer div
element with the id "outer" and an inner div
element with the id "inner". Two event listeners are attached to these elements using the addEventListener
method. The first listener is attached to the outer element with useCapture
set to false
, indicating the bubbling phase. The second listener is attached to the inner element with useCapture
set to true
, indicating the capturing phase.
When you click on the inner element, both event handlers will be called, but their behavior will differ based on the value of useCapture
. The console logs will show the difference in event.target.id
(the clicked element) and event.currentTarget.id
(the element to which the event listener is attached).
Is there a way to stop an event from bubbling up?
View Answer:
How can you stop event propagation in JavaScript?
View Answer:
HTML:
<div id="outer">
<div id="inner">
<button id="button">Click me!</button>
</div>
</div>
JavaScript:
document.getElementById("outer").addEventListener("click", function(event) {
console.log("Outer div clicked");
});
document.getElementById("inner").addEventListener("click", function(event) {
console.log("Inner div clicked");
event.stopPropagation(); // Stops event propagation
});
document.getElementById("button").addEventListener("click", function(event) {
console.log("Button clicked");
});
Only the following output will be logged to the console:
Inner div clicked
The event propagation is prevented from reaching the outer div's event listener due to the call to event.stopPropagation()
within the event listener of the inner div.
Can we stop all functions from running on a given event?
View Answer:
<div id="outer">
<div id="inner">
Click me
</div>
</div>
<script>
function outerClick(event) {
console.log("Outer clicked");
}
function innerClick(event) {
console.log("Inner clicked");
event.stopPropagation();
}
var outerElement = document.getElementById("outer");
var innerElement = document.getElementById("inner");
outerElement.addEventListener("click", outerClick);
innerElement.addEventListener("click", innerClick);
</script>
In this example, we have an outer div
element with the id "outer" and an inner div
element with the id "inner". Two event listeners are attached to these elements using the addEventListener
method.
When you click on the inner element, the innerClick
event handler will be triggered. It logs "Inner clicked" to the console and calls event.stopPropagation()
to stop the event from propagating further. As a result, the outerClick
event handler will not be triggered, and "Outer clicked" will not be logged to the console.
What's the difference between stopPropagation and stopImmediatePropagation methods?
View Answer:
HTML:
<div id="myElement">
<button id="myButton">Click me!</button>
</div>
JavaScript:
document.getElementById("myElement").addEventListener("click", function(event) {
console.log("Event captured");
});
document.getElementById("myButton").addEventListener("click", function(event) {
console.log("Button clicked");
event.stopPropagation(); // Stops propagation to parent elements
});
document.getElementById("myButton").addEventListener("click", function(event) {
console.log("Additional listener on button");
event.stopImmediatePropagation(); // Stops further listeners on the same element
});
document.getElementById("myElement").addEventListener("click", function(event) {
console.log("Additional listener on element");
});
Output:
Button clicked
The "Additional listener on button" and "Additional listener on element" event listeners are not triggered due to the use of event.stopImmediatePropagation()
.
Does stopping event propagation prevent default actions?
View Answer:
How does event delegation relate to event bubbling?
View Answer:
HTML:
<ul id="myList">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
</ul>
JavaScript:
document.querySelector("#myList").addEventListener("click", function(e) {
if(e.target && e.target.nodeName === "LI") {
console.log("List item ", e.target.textContent, " was clicked");
}
});
Output:
"List item ", "Item 1", " was clicked"
"List item ", "Item 2", " was clicked"
"List item ", "Item 3", " was clicked"
What is the default direction of event propagation?
View Answer:
<div id="outer">
<div id="inner">
Click me
</div>
</div>
<script>
function outerClick(event) {
console.log("Outer clicked");
}
function innerClick(event) {
console.log("Inner clicked");
}
var outerElement = document.getElementById("outer");
var innerElement = document.getElementById("inner");
outerElement.addEventListener("click", outerClick);
innerElement.addEventListener("click", innerClick);
</script>
In this example, we have an outer div
element with the id "outer" and an inner div
element with the id "inner". Two event listeners are attached to these elements using the addEventListener
method.
When you click on the inner element, both the innerClick
and outerClick
event handlers will be triggered. The events will propagate from the innermost element (inner) to its parent elements (outer) in the default direction of event bubbling. The console logs will show "Inner clicked" followed by "Outer clicked".
What are the three phases of event propagation?
View Answer:
How can you determine the phase of event propagation?
View Answer:
<div id="outer">
<div id="inner">
Click me
</div>
</div>
<script>
function handleClick(event) {
if (event.eventPhase === Event.CAPTURING_PHASE) {
console.log("Event capturing phase");
} else if (event.eventPhase === Event.AT_TARGET) {
console.log("Event target phase");
} else if (event.eventPhase === Event.BUBBLING_PHASE) {
console.log("Event bubbling phase");
}
}
var outerElement = document.getElementById("outer");
var innerElement = document.getElementById("inner");
outerElement.addEventListener("click", handleClick, true); // Capturing phase
innerElement.addEventListener("click", handleClick); // Bubbling phase
</script>
In this example, we have an outer div
element with the id "outer" and an inner div
element with the id "inner". Two event listeners are attached to these elements, one in the capturing phase and the other in the bubbling phase.
When you click on the inner element, the handleClick
event handler will be called for both elements. Inside the event handler, we check the event.eventPhase
property to determine the phase of event propagation. The corresponding message will be logged to the console based on the event phase detected.
Can you modify the default direction of event propagation?
View Answer:
Is there a straightforward way to invoke capturing an event in the capturing phase?
View Answer:
<style>
body * {
margin: 10px;
border: 1px solid blue;
}
</style>
<form>
FORM
<div>
DIV
<p>P</p>
</div>
</form>
<script>
for (let elem of document.querySelectorAll('*')) {
elem.addEventListener(
'click',
(e) => alert(`Capturing: ${elem.tagName}`),
true
);
elem.addEventListener('click', (e) => alert(`Bubbling: ${elem.tagName}`));
}
</script>
While there are three phases, the second ("target phase": the event reached the element) is not handled independently in theory: handlers from both the capturing and bubbling phases fire at that time.