JavaScript onclick Not As Bad As They Say Let Me Prove It!
MkDay
Posted on November 15, 2021
Warning!
MDN docs recommands addEventListener
instead of onclick
as follows.
The addEventListener() method is the recommended way to register an event listener. The benefits are as follows:
It allows adding more than one handler for an event. This is particularly useful for libraries, JavaScript modules, or any other kind of code that needs to work well with other libraries or extensions.
In contrast to using an onXYZ property, it gives you finer-grained control of the phase when the listener is activated (capturing vs. bubbling).
It works on any event target, not just HTML or SVG elements.
It sounds like a discouraging statement about the use of onclick
. However, onclick
can compete with addEventListener
for the most part.
To prove that, let's consider the following simple program.
There are a child button
element and its parent div
element. And there is a function named calculate to use as the event handler when the button
gets clicked.
HTML
<div id="container">
<button id="btn-add">Add</button>
</div>
onclick Works Well For The Following Use-cases
1. Event Delegation (Multiple elements - single handler)
Using event delegation, we can add one event handler only for the parent element and recognize the current child element that the click event is occurred on, using event.target.matches()
.
let container = document.querySelector('#container');
let addBtn = document.querySelector('#btn-add');
let num1 = 6;
let num2 = 2;
let result = 0;
function calculate(e) {
if(e.target && e.target.matches('#btn-add')) {
result += num1 + num2;
console.log(`result: ${result}`);
}
}
Event delegation - addEventListener
//addEventListener
container.addEventListener('click', calculate);
// output after clicking the button 3 times.
/*
"result: 8"
"result: 16"
"result: 24"
*/
Event delegation - onclick
//onclick
container.onclick = calculate;
// output after clicking the button 3 times.
/*
"result: 8"
"result: 16"
"result: 24"
*/
2. Event Bubbling & Capture
I don't suppose to explain bubbling and capturing here. However, it is good to mention that the bubbling event is the default behavior of almost every modern browser.
The addEventListener
has an option to use event bubbling or capture and, it is pretty clear that there is no such option with onclick
for the capturing phase.
let container = document.querySelector('#container');
let addBtn = document.querySelector('#btn-add');
let num1 = 6;
let num2 = 2;
let result = 0;
function calculate(e) {
result += num1 + num2;
console.log(`calculated result: ${result}`);
}
First, we retrieve the calculated result using the event handler of the button
.
And then display the result on the div
as the current result.
Bubbling works well in this case for both onclick
and addEventListener
.
Bubbling - addEventListener
// addEventListener - bubbling
// display current result after calculating
container.addEventListener('click', function() {
console.log(`current result: ${result}`);
});
addBtn.addEventListener('click', calculate);
// output after clicking the button 3 times.
/*
"calculated result: 8"
"current result: 8"
"calculated result: 16"
"current result: 16"
"calculated result: 24"
"current result: 24"
*/
Bubbling - onclick
// onclick - bubbling
// display current result after calculating
container.onclick = function() {
console.log(`current result: ${result}`);
}
addBtn.onclick = calculate;
// output after clicking the button 3 times.
/*
"calculated result: 8"
"current result: 8"
"calculated result: 16"
"current result: 16"
"calculated result: 24"
"current result: 24"
*/
Now we first display the result as previous result on the div
and then retrieve the calculated result using the event handler of the button
.
Here we specify the optional argument of the addEventListener
which is, useCapture as true for the parent element.
Capture - addEventListener
// addEventListener - capturing
// display previous result before calculating
container.addEventListener('click', function() {
console.log(`previous result: ${result}`);
}, true);
addBtn.addEventListener('click', calculate);
// output after clicking the button 3 times.
/*
"previous result: 0"
"calculated result: 8"
"previous result: 8"
"calculated result: 16"
"previous result: 16"
"calculated result: 24"
*/
We cannot use the event capture with the onclick
. However, this is kind of achievable using event delegation.
Capture - onclick (using event delegation)
// onclick - capturing
// display previous result before calculating
container.onclick = function(e) {
console.log(`previous result: ${result}`);
if(e.target && e.target.matches('#btn-add')) {
calculate();
}
}
// output after clicking the button 3 times.
/*
"previous result: 0"
"calculated result: 8"
"previous result: 8"
"calculated result: 16"
"previous result: 16"
"calculated result: 24"
*/
3. Remove event listeners
Here we add the num1 + num2
to the result
only once and stop listening to the event after the first click has occurred.
There is a method called removeEventListener
, which accepts the same arguments that assigned to the addEventListener
previously. It removes the previously-added event listener from the element.
let container = document.querySelector('#container');
let addBtn = document.querySelector('#btn-add');
let num1 = 6;
let num2 = 2;
let result = 0;
function calculate(e) {
result += num1 + num2;
console.log(`element: button - result: ${result}`);
}
addEventListener - before removing listener
container.addEventListener('click', function(e) {
console.log(`element: div - result: ${result}`);
});
addBtn.addEventListener('click', calculate);
// output after clicking the button 3 times.
/*
"element: button - result: 8"
"element: div - result: 8"
"element: button - result: 16"
"element: div - result: 16"
"element: button - result: 24"
"element: div - result: 24"
*/
addEventListener - after removing listener
container.addEventListener('click', function(e) {
addBtn.removeEventListener('click', calculate);
console.log(`element: div - result: ${result}`);
});
addBtn.addEventListener('click', calculate);
// output after clicking the button 3 times.
/*
"element: button - result: 8"
"element: div - result: 8"
"element: div - result: 8"
"element: div - result: 8"
*/
There is no obvious way to remove the onclick
event, but if we make the onclick
attribute as null
it will do the job as we supposed.
onclick - before removing listener
container.onclick = function(e) {
console.log(`element: div - result: ${result}`);
}
addBtn.onclick = calculate;
// output after clicking the button 3 times.
/*
"element: button - result: 8"
"element: div - result: 8"
"element: button - result: 16"
"element: div - result: 16"
"element: button - result: 24"
"element: div - result: 24"
*/
onclick - after removing listener
container.onclick = function(e) {
addBtn.onclick = null;
console.log(`element: div - result: ${result}`);
}
addBtn.onclick = calculate;
// output after clicking the button 3 times.
/*
"element: button - result: 8"
"element: div - result: 8"
"element: div - result: 8"
"element: div - result: 8"
*/
No Options Other Than addEventListener
1. Event Overwriting (Single element - multiple handlers)
The addEventListener
works well with the following two handlers.
- First handler - calculate: calculates the result.
- Second handler - showResult: shows the result.
If we use onclick
in this case, the second handler will overwrite the first one, so we will never get the calculated result.
let container = document.querySelector('#container');
let addBtn = document.querySelector('#btn-add');
let num1 = 6;
let num2 = 2;
let result = 0;
function calculate(e) {
if(e.target) {
result += num1 + num2;
}
}
function showResult(e) {
if(e.target) {
console.log(`result: ${result}`);
}
}
Using addEventListener
// addEventListener
addBtn.addEventListener('click', calculate);
addBtn.addEventListener('click', showResult);
// output after clicking the button 3 times.
/*
"result: 8"
"result: 16"
"result: 24"
*/
Using onclick
// onclick
addBtn.onclick = calculate;
addBtn.onclick = showResult;
// output after clicking the button 3 times.
/*
"result: 0"
"result: 0"
"result: 0"
*/
Let's Summarize
Now you can see onclick
can do almost everything except registering multiple handlers to a single element. However, it is good to mention that there are many things to consider before selecting the right one for your specific needs. This post is just here to prove that there are still some cases where we can use onclick
.
Image Credit: Artem Bryzgalov on Unsplash
Posted on November 15, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
November 22, 2024