Event Delegation
Browser Events: Event Delegation
What is event delegation in JavaScript?
View Answer:
Consider a list where we want to handle clicks on any item:
HTML:
<ul id="myList">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<!-- More items can be dynamically added -->
</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");
}
});
In this example, we attach a single event listener to the parent ul
element, rather than individual listeners to each li
. This is more efficient and works for dynamically added items as well.
Why would you use event delegation?
View Answer:
How does event delegation take advantage of event bubbling?
View Answer:
How does event delegation handle events on elements that don’t exist at the time of binding?
View Answer:
Consider a scenario where list items are added dynamically to a list, and we want to handle clicks on these new items.
HTML:
<button id="add">Add Item</button>
<ul id="myList">
<!-- Items will be dynamically added here -->
</ul>
JavaScript:
document.querySelector("#add").addEventListener("click", function() {
const li = document.createElement("li");
li.textContent = "New Item";
document.querySelector("#myList").appendChild(li);
});
document.querySelector("#myList").addEventListener("click", function(e) {
if(e.target && e.target.nodeName === "LI") {
console.log("List item ", e.target.textContent, " was clicked");
}
});
Here, even though new list items ("li") are created after the event listeners are attached, clicks on these new items are still correctly handled. This is because the event listener is attached to the parent ("ul"), and events bubble up.
How can you determine which element triggered an event in an event delegation setup?
View Answer:
Here's an example where we handle clicks on items in a list using event delegation, and determine which item was clicked.
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("The element that triggered the event is: ", e.target);
}
});
In this scenario, clicking on an item in the list will log the item element to the console. The clicked element is identified using the event.target
property in the event handler function.
How does event delegation affect memory usage?
View Answer:
HTML:
<div id="parent">
<button class="child">Button 1</button>
<button class="child">Button 2</button>
<button class="child">Button 3</button>
</div>
JavaScript: We are targeting the parent
instead of each individual child.
document.getElementById('parent').addEventListener('click', function(event) {
if (event.target.classList.contains('child')) {
console.log('Button clicked:', event.target.textContent);
}
});
What is the role of the "event.target" property in event delegation?
View Answer:
Can event delegation handle events on elements outside of the element it's bound to?
View Answer:
Let's consider two lists - one where the event listener is bound, and another separate list.
HTML:
<ul id="myList">
<li>Item 1</li>
<li>Item 2</li>
</ul>
<ul id="otherList">
<li>Other Item 1</li>
<li>Other Item 2</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 in myList");
}
});
document.querySelector("#otherList").addEventListener("click", function(e) {
if(e.target && e.target.nodeName === "LI") {
console.log("List item ", e.target.textContent, " was clicked in otherList");
}
});
In this scenario, clicking items in myList
will trigger its own event listener, and clicking items in otherList
will trigger its own listener. The listener on myList
won't react to clicks in otherList
and vice versa because they are outside of each other's hierarchies.
What is the main disadvantage of event delegation?
View Answer:
Here's an example that demonstrates the limitations of event delegation with focus, blur, and mouseenter events:
<div id="parent">
<input type="text" class="child" placeholder="Input 1">
<input type="text" class="child" placeholder="Input 2">
<input type="text" class="child" placeholder="Input 3">
</div>
document.getElementById('parent').addEventListener('focus', function(event) {
console.log('Input focused:', event.target.placeholder);
}, true); // Using the "capture" phase
document.getElementById('parent').addEventListener('blur', function(event) {
console.log('Input blurred:', event.target.placeholder);
}, true); // Using the "capture" phase
document.getElementById('parent').addEventListener('mouseenter', function(event) {
console.log('Mouse entered:', event.target.placeholder);
});
In this example, we attempt to use event delegation with focus, blur, and mouseenter events. However, due to the nature of these events, they don't naturally bubble up through the DOM tree. To capture these events, we need to use the "capture" phase by passing true
as the third argument to the addEventListener
method. Even with this approach, event delegation with these events might not work as expected or may require additional workarounds, making it less suitable for delegation compared to other events that naturally bubble up.
What is the behavior pattern in terms of event delegation?
View Answer:
<!-- Counter: -->
<input type="button" value="1" data-counter />
<!-- One more counter: -->
<input type="button" value="2" data-counter />
<script>
document.addEventListener('click', function (event) {
if (event.target.dataset.counter != undefined) {
// if the attribute exists...
event.target.value++;
}
});
</script>
What exactly is event bubbling/event propagation in JavaScript?
View Answer:
Is it possible to prevent event bubbling in JavaScript?
View Answer:
Element.handleOnClick = (event) => {
event.stopPropagation();
// Add code to handle the event here
}
What is a good use-case for event delegation?
View Answer:
document.getElementById("app").innerHTML = `
<h1>Current Users</h1>
<ul id="itemList">
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
<li>Item 6</li>
<li>Item 7</li>
<li>Item 8</li>
</ul>
`;
document.getElementById("itemList").addEventListener("click", (event) => {
console.log(event.type);
});