DEV Community

Cover image for JavaScript onclick Not As Bad As They Say Let Me Prove It!
MkDay
MkDay

Posted on

JavaScript onclick Not As Bad As They Say Let Me Prove It!

Warning!

MDN docs recommands addEventListener instead of onclick as follows.

It says,

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>

Enter fullscreen mode Exit fullscreen mode

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}`);
    }    
}

Enter fullscreen mode Exit fullscreen mode
Event delegation - addEventListener

//addEventListener
container.addEventListener('click', calculate);

// output after clicking the button 3 times.
/*
"result: 8"
"result: 16"
"result: 24"
*/

Enter fullscreen mode Exit fullscreen mode
Event delegation - onclick

//onclick
container.onclick = calculate;

// output after clicking the button 3 times.
/*
"result: 8"
"result: 16"
"result: 24"
*/

Enter fullscreen mode Exit fullscreen mode

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}`);
}

Enter fullscreen mode Exit fullscreen mode

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"
*/

Enter fullscreen mode Exit fullscreen mode
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"
*/

Enter fullscreen mode Exit fullscreen mode

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"
*/

Enter fullscreen mode Exit fullscreen mode

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"
*/

Enter fullscreen mode Exit fullscreen mode

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}`);
}

Enter fullscreen mode Exit fullscreen mode
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"
*/

Enter fullscreen mode Exit fullscreen mode
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"
*/

Enter fullscreen mode Exit fullscreen mode

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"
*/

Enter fullscreen mode Exit fullscreen mode
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"
*/

Enter fullscreen mode Exit fullscreen mode

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}`); 
  }
}

Enter fullscreen mode Exit fullscreen mode
Using addEventListener
// addEventListener

addBtn.addEventListener('click', calculate);
addBtn.addEventListener('click', showResult); 

// output after clicking the button 3 times.
/*
"result: 8"
"result: 16"
"result: 24"
*/

Enter fullscreen mode Exit fullscreen mode
Using onclick
// onclick

addBtn.onclick = calculate;
addBtn.onclick = showResult; 

// output after clicking the button 3 times.
/*
"result: 0"
"result: 0"
"result: 0"
*/

Enter fullscreen mode Exit fullscreen mode

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

Discussion (0)