addEventListener() function vs on property
There are two different ways to handle an event of element. The following piece of code demonstrates how to handle the click
event with the addEventListener
function:
const handler = () => {
console.log('the element is clicked');
};
element.addEventListener('click', handler);
The other way is to use the onclick
property or inline onclick
attribute such as:
element.onclick = handler;
<div onclick="handler()" />
<div onclick="javascript: handler()" />
Differences
You can add multiple handlers for an event with
addEventListener
.The
on___
property or attribute allows to register only one handler. Settingon___
will remove all existing handlers.In the following sample code, clicking the element will print
onclick is used
in Console because theonclick
removes the originalhandler
.const handler = () => {
console.log('addEventListener is used');
};
element.addEventListener('click', handler);
const anotherHandler = () => {
console.log('onclick is used');
};
element.onclick = anotherHandler;With
addEventListener
, it's possible for us to handle the event in either capturing or bubbling phase by passing. Theon___
property doesn't support that.Assume that we have two
div
element as following:<div id="parent">
Parent
<div id="child">Child</div>
</div>We are going to add handlers for the
click
event:const handleParentClick = () => {
console.log('parent is clicked');
};
const handleChildClick = () => {
console.log('child is clicked');
};Setting the third parameter of
addEventListener
totrue
orfalse
could change the order of handler execution.// We will see "child is clicked" and then
// "parent is clicked" when clicking the child element
// The `click` event is passed from the bottom node
// up to its parents
document.getElementById('parent').addEventListener('click', handleParentClick, false);
document.getElementById('child').addEventListener('click', handleChildClick, false);In contrast with the bubbling phase, the following code will make the
click
event is passed from parents down to its children:// We will see "parent is clicked" and then
// "child is clicked" when clicking the child element
document.getElementById('parent').addEventListener('click', handleParentClick, true);
document.getElementById('child').addEventListener('click', handleChildClick, true);The last thing is the browser compatibility. The
addEventListener
function doesn't work before Internet Explorer (IE) 9, whileonclick
is supported by all browsers. The IE 8 and older versions use theattachEvent
function.It isn't really important thing in the web development today as most websites don't support IE 8 or 9 anymore. But if you still need to take care of IE 8 (really?), then here is the small line of code that fills the gap:
element.attachEvent ? element.attachEvent('onclick', handler) : element.addEventListener('click', handler);
Good practices
Always pick
addEventListener
There are a couple of problems with setting
onclick
attribute. It has a potential security issue since we pass a string. The browser also doesn't warn if the method passed toonclick
attribute doesn't exist.But you often see that the event handlers are set on element's attributes in modern JavaScript frameworks, such as:
Angular:
<button (click)="sayHello()">Hello</button>
React:
<button onClick="{sayHello}">Hello</button>
Vue:
<button v-on:click="sayHello">Hello</button>
It's designed in a declarative way, so it's easy for developers to get used to the library. Despite the fact that the declaration looks similar to the
onclick
attribute, the framework parses the code, and transpiles it toaddEventListener
method.To avoid the memory leak issue, remember to remove the handler when it's not used anymore.
const handler = (e) => {
...
};
// Attach event listener
element.addEventListener('click', handler);
// Remove it later
element.removeEventListener('click', handler);In the web development nowadays, an element in a single page application might be added and removed from page automatically. The popular JavaScript provides the moments that we can hook on to setup and clean up event handlers.
The sample code below demonstrates the similar actions with React library:
class Resize extends React.Component {
const handleResize = (e) => {
...
};
componentDidMount() {
window.addEventListener('resize', this.handleResize);
}
componentWillUnmount() {
window.removeEventListener('resize', this.handleResize);
}
}