Mastering the Javascript event system (Part 3, Additional examples for handling events.)
This is the third post in a series about working with Javascript events and using a single event listener to handle related elements.
Extra examples addendum
Here are some additional examples to demonstrate how to take advantage of a single event listener.
Lists
A common pattern is to have a list of items that can be interacted with, where new items are inserted dynamically with Javascript. If you have event listeners attached to each item, then your code has to deal with event listeners every time you generate a new element.
<div id="buttons-container"></div><button id="add">Add new button</button>let buttonCounter = 0;
document.getElementById('add').addEventListener('click', evt => {
const newButton = document.createElement('button');
newButton.dataset.number = buttonCounter;
// Make a new event listener every time "Add new button" is clicked
newButton.addEventListener('click', evt => {
// When clicked, log the clicked button's number.
console.log(`Clicked button #${newButton.dataset.number}`);
});
buttonCounter++; const container = document.getElementById('buttons-container');
container.appendChild(newButton);
});
By taking advantage of bubbling, you can just have a single event listener on the container. If you create many elements in your app, this reduces the number of listeners from n to 2.
let buttonCounter = 0;
document.getElementById('add').addEventListener('click', evt => {
const newButton = document.createElement('button');
newButton.dataset.number = buttonCounter;
buttonCounter++; const container = document.getElementById('buttons-container');
container.appendChild(newButton);
});
document.getElementById('buttons-container').addEventListener('click', evt => {
const clickedButton = evt.target.closest('button');
if (clickedButton != null) {
// When clicked, log the clicked button's number.
console.log(`Clicked button #${clickedButton.dataset.number}`);
}
});
Forms
Perhaps you have a form with lots of inputs, and you want to collect all the user responses into a single object.
<form>
<label>Name: <input name="name" type="text"/></label>
<label>Email: <input name="email" type="email"/></label>
<label>Password: <input name="password" type="password"/></label>
</form>let responses = {
name: '',
email: '',
password: ''
};document.querySelector('input[name="name"]')
.addEventListener('change', evt => {
const inputElement = document.querySelector('input[name="name"]');
responses.name = inputElement.value;
});
document.querySelector('input[name="email"]')
.addEventListener('change', evt => {
const inputElement = document.querySelector('input[name="email"]');
responses.email = inputElement.value;
});
document.querySelector('input[name="password"]')
.addEventListener('change', evt => {
const inputElement = document.querySelector('input[name="password"]');
responses.password = inputElement.value;
});
Let’s switch to a single listener on the parent <form>
element instead.
let responses = {
name: '',
email: '',
password: ''
};document.querySelector('form').addEventListener('change', evt => {
responses[evt.target.name] = evt.target.value;
});