HTML events VS Javascript events [duplicate] - javascript

What's the difference between addEventListener and onclick?
var h = document.getElementById("a");
h.onclick = dothing1;
h.addEventListener("click", dothing2);
The code above resides together in a separate .js file, and they both work perfectly.

Both are correct, but none of them are "best" per se, and there may be a reason the developer chose to use both approaches.
Event Listeners (addEventListener and IE's attachEvent)
Earlier versions of Internet Explorer implement JavaScript differently from pretty much every other browser. With versions less than 9, you use the attachEvent[doc] method, like this:
element.attachEvent('onclick', function() { /* do stuff here*/ });
In most other browsers (including IE 9 and above), you use addEventListener[doc], like this:
element.addEventListener('click', function() { /* do stuff here*/ }, false);
Using this approach (DOM Level 2 events), you can attach a theoretically unlimited number of events to any single element. The only practical limitation is client-side memory and other performance concerns, which are different for each browser.
The examples above represent using an anonymous function[doc]. You can also add an event listener using a function reference[doc] or a closure[doc]:
var myFunctionReference = function() { /* do stuff here*/ }
element.attachEvent('onclick', myFunctionReference);
element.addEventListener('click', myFunctionReference , false);
Another important feature of addEventListener is the final parameter, which controls how the listener reacts to bubbling events[doc]. I've been passing false in the examples, which is standard for probably 95% of use cases. There is no equivalent argument for attachEvent, or when using inline events.
Inline events (HTML onclick="" property and element.onclick)
In all browsers that support javascript, you can put an event listener inline, meaning right in the HTML code. You've probably seen this:
<a id="testing" href="#" onclick="alert('did stuff inline');">Click me</a>
Most experienced developers shun this method, but it does get the job done; it is simple and direct. You may not use closures or anonymous functions here (though the handler itself is an anonymous function of sorts), and your control of scope is limited.
The other method you mention:
element.onclick = function () { /*do stuff here */ };
... is the equivalent of inline javascript except that you have more control of the scope (since you're writing a script rather than HTML) and can use anonymous functions, function references, and/or closures.
The significant drawback with inline events is that unlike event listeners described above, you may only have one inline event assigned. Inline events are stored as an attribute/property of the element[doc], meaning that it can be overwritten.
Using the example <a> from the HTML above:
var element = document.getElementById('testing');
element.onclick = function () { alert('did stuff #1'); };
element.onclick = function () { alert('did stuff #2'); };
... when you clicked the element, you'd only see "Did stuff #2" - you overwrote the first assigned of the onclick property with the second value, and you overwrote the original inline HTML onclick property too. Check it out here: http://jsfiddle.net/jpgah/.
Broadly speaking, do not use inline events. There may be specific use cases for it, but if you are not 100% sure you have that use case, then you do not and should not use inline events.
Modern Javascript (Angular and the like)
Since this answer was originally posted, javascript frameworks like Angular have become far more popular. You will see code like this in an Angular template:
<button (click)="doSomething()">Do Something</button>
This looks like an inline event, but it isn't. This type of template will be transpiled into more complex code which uses event listeners behind the scenes. Everything I've written about events here still applies, but you are removed from the nitty gritty by at least one layer. You should understand the nuts and bolts, but if your modern JS framework best practices involve writing this kind of code in a template, don't feel like you're using an inline event -- you aren't.
Which is Best?
The question is a matter of browser compatibility and necessity. Do you need to attach more than one event to an element? Will you in the future? Odds are, you will. attachEvent and addEventListener are necessary. If not, an inline event may seem like they'd do the trick, but you're much better served preparing for a future that, though it may seem unlikely, is predictable at least. There is a chance you'll have to move to JS-based event listeners, so you may as well just start there. Don't use inline events.
jQuery and other javascript frameworks encapsulate the different browser implementations of DOM level 2 events in generic models so you can write cross-browser compliant code without having to worry about IE's history as a rebel. Same code with jQuery, all cross-browser and ready to rock:
$(element).on('click', function () { /* do stuff */ });
Don't run out and get a framework just for this one thing, though. You can easily roll your own little utility to take care of the older browsers:
function addEvent(element, evnt, funct){
if (element.attachEvent)
return element.attachEvent('on'+evnt, funct);
else
return element.addEventListener(evnt, funct, false);
}
// example
addEvent(
document.getElementById('myElement'),
'click',
function () { alert('hi!'); }
);
Try it: http://jsfiddle.net/bmArj/
Taking all of that into consideration, unless the script you're looking at took the browser differences into account some other way (in code not shown in your question), the part using addEventListener would not work in IE versions less than 9.
Documentation and Related Reading
W3 HTML specification, element Event Handler Attributes
element.addEventListener on MDN
element.attachEvent on MSDN
Jquery.on
quirksmode blog "Introduction to Events"
CDN-hosted javascript libraries at Google

The difference you could see if you had another couple of functions:
var h = document.getElementById('a');
h.onclick = doThing_1;
h.onclick = doThing_2;
h.addEventListener('click', doThing_3);
h.addEventListener('click', doThing_4);
Functions 2, 3 and 4 work, but 1 does not. This is because addEventListener does not overwrite existing event handlers, whereas onclick overrides any existing onclick = fn event handlers.
The other significant difference, of course, is that onclick will always work, whereas addEventListener does not work in Internet Explorer before version 9. You can use the analogous attachEvent (which has slightly different syntax) in IE <9.

In this answer I will describe the three methods of defining DOM event handlers.
element.addEventListener()
Code example:
const element = document.querySelector('a');
element.addEventListener('click', event => event.preventDefault(), true);
Try clicking this link.
element.addEventListener() has multiple advantages:
Allows you to register unlimited events handlers and remove them with element.removeEventListener().
Has useCapture parameter, which indicates whether you'd like to handle event in its capturing or bubbling phase. See: Unable to understand useCapture attribute in addEventListener.
Cares about semantics. Basically, it makes registering event handlers more explicit. For a beginner, a function call makes it obvious that something happens, whereas assigning event to some property of DOM element is at least not intuitive.
Allows you to separate document structure (HTML) and logic (JavaScript). In tiny web applications it may not seem to matter, but it does matter with any bigger project. It's way much easier to maintain a project which separates structure and logic than a project which doesn't.
Eliminates confusion with correct event names. Due to using inline event listeners or assigning event listeners to .onevent properties of DOM elements, lots of inexperienced JavaScript programmers thinks that the event name is for example onclick or onload. on is not a part of event name. Correct event names are click and load, and that's how event names are passed to .addEventListener().
Works in almost all browser. If you still have to support IE <= 8, you can use a polyfill from MDN.
element.onevent = function() {} (e.g. onclick, onload)
Code example:
const element = document.querySelector('a');
element.onclick = event => event.preventDefault();
Try clicking this link.
This was a way to register event handlers in DOM 0. It's now discouraged, because it:
Allows you to register only one event handler. Also removing the assigned handler is not intuitive, because to remove event handler assigned using this method, you have to revert onevent property back to its initial state (i.e. null).
Doesn't respond to errors appropriately. For example, if you by mistake assign a string to window.onload, for example: window.onload = "test";, it won't throw any errors. Your code wouldn't work and it would be really hard to find out why. .addEventListener() however, would throw error (at least in Firefox): TypeError: Argument 2 of EventTarget.addEventListener is not an object.
Doesn't provide a way to choose if you want to handle event in its capturing or bubbling phase.
Inline event handlers (onevent HTML attribute)
Code example:
Try clicking this link.
Similarly to element.onevent, it's now discouraged. Besides the issues that element.onevent has, it:
Is a potential security issue, because it makes XSS much more harmful. Nowadays websites should send proper Content-Security-Policy HTTP header to block inline scripts and allow external scripts only from trusted domains. See How does Content Security Policy work?
Doesn't separate document structure and logic.
If you generate your page with a server-side script, and for example you generate a hundred links, each with the same inline event handler, your code would be much longer than if the event handler was defined only once. That means the client would have to download more content, and in result your website would be slower.
See also
EventTarget.addEventListener() documentation (MDN)
EventTarget.removeEventListener() documentation (MDN)
onclick vs addEventListener
dom-events tag wiki

While onclick works in all browsers, addEventListener does not work in older versions of Internet Explorer, which uses attachEvent instead.
The downside of onclick is that there can only be one event handler, while the other two will fire all registered callbacks.

Summary:
addEventListener can add multiple events, whereas with onclick this cannot be done.
onclick can be added as an HTML attribute, whereas an addEventListener can only be added within <script> elements.
addEventListener can take a third argument which can stop the event propagation.
Both can be used to handle events. However, addEventListener should be the preferred choice since it can do everything onclick does and more. Don't use inline onclick as HTML attributes as this mixes up the javascript and the HTML which is a bad practice. It makes the code less maintainable.

As far as I know, the DOM "load" event still does only work very limited. That means it'll only fire for the window object, images and <script> elements for instance. The same goes for the direct onload assignment. There is no technical difference between those two. Probably .onload = has a better cross-browser availabilty.
However, you cannot assign a load event to a <div> or <span> element or whatnot.

An element can have only one event handler attached per event type, but can have multiple event listeners.
So, how does it look in action?
Only the last event handler assigned gets run:
const button = document.querySelector(".btn")
button.onclick = () => {
console.log("Hello World");
};
button.onclick = () => {
console.log("How are you?");
};
button.click() // "How are you?"
All event listeners will be triggered:
const button = document.querySelector(".btn")
button.addEventListener("click", event => {
console.log("Hello World");
})
button.addEventListener("click", event => {
console.log("How are you?");
})
button.click()
// "Hello World"
// "How are you?"
IE Note: attachEvent is no longer supported. Starting with IE 11, use addEventListener: docs.

One detail hasn't been noted yet: modern desktop browsers consider different button presses to be "clicks" for AddEventListener('click' and onclick by default.
On Chrome 42 and IE11, both onclick and AddEventListener click fire on left and middle click.
On Firefox 38, onclick fires only on left click, but AddEventListener click fires on left, middle and right clicks.
Also, middle-click behavior is very inconsistent across browsers when scroll cursors are involved:
On Firefox, middle-click events always fire.
On Chrome, they won't fire if the middleclick opens or closes a scroll cursor.
On IE, they fire when scroll cursor closes, but not when it opens.
It is also worth noting that "click" events for any keyboard-selectable HTML element such as input also fire on space or enter when the element is selected.

element.onclick = function() { /* do stuff */ }
element.addEventListener('click', function(){ /* do stuff */ },false);
They apparently do the same thing: listen for the click event and execute a callback function. Nevertheless, they’re not equivalent. If you ever need to choose between the two, this could help you to figure out which one is the best for you.
The main difference is that onclick is just a property, and like all object properties, if you write on more than once, it will be overwritten. With addEventListener() instead, we can simply bind an event handler to the element, and we can call it each time we need it without being worried of any overwritten properties.
Example is shown here,
Try it: https://jsfiddle.net/fjets5z4/5/
In first place I was tempted to keep using onclick, because it’s shorter and looks simpler… and in fact it is. But I don’t recommend using it anymore. It’s just like using inline JavaScript. Using something like – that’s inline JavaScript – is highly discouraged nowadays (inline CSS is discouraged too, but that’s another topic).
However, the addEventListener() function, despite it’s the standard, just doesn’t work in old browsers (Internet Explorer below version 9), and this is another big difference. If you need to support these ancient browsers, you should follow the onclick way. But you could also use jQuery (or one of its alternatives): it basically simplifies your work and reduces the differences between browsers, therefore can save you a lot of time.
var clickEvent = document.getElementByID("onclick-eg");
var EventListener = document.getElementByID("addEventListener-eg");
clickEvent.onclick = function(){
window.alert("1 is not called")
}
clickEvent.onclick = function(){
window.alert("1 is not called, 2 is called")
}
EventListener.addEventListener("click",function(){
window.alert("1 is called")
})
EventListener.addEventListener("click",function(){
window.alert("2 is also called")
})

Javascript tends to blend everything into objects and that can make it confusing. All into one is the JavaScript way.
Essentially onclick is a HTML attribute. Conversely addEventListener is a method on the DOM object representing a HTML element.
In JavaScript objects, a method is merely a property that has a function as a value and that works against the object it is attached to (using this for example).
In JavaScript as HTML element represented by DOM will have it's attributes mapped onto its properties.
This is where people get confused because JavaScript melds everything into a single container or namespace with no layer of indirection.
In a normal OO layout (which does at least merge the namespace of properties/methods) you would might have something like:
domElement.addEventListener // Object(Method)
domElement.attributes.onload // Object(Property(Object(Property(String))))
There are variations like it could use a getter/setter for onload or HashMap for attributes but ultimately that's how it would look. JavaScript eliminated that layer of indirection at the expect of knowing what's what among other things. It merged domElement and attributes together.
Barring compatibility you should as a best practice use addEventListener. As other answers talk about the differences in that regard rather than the fundamental programmatic differences I will forgo it. Essentially, in an ideal world you're really only meant to use on* from HTML but in an even more ideal world you shouldn't be doing anything like that from HTML.
Why is it dominant today? It's quicker to write, easier to learn and tends to just work.
The whole point of onload in HTML is to give access to the addEventListener method or functionality in the first place. By using it in JS you're going through HTML when you could be applying it directly.
Hypothetically you can make your own attributes:
$('[myclick]').each(function(i, v) {
v.addEventListener('click', function() {
eval(v.myclick); // eval($(v).attr('myclick'));
});
});
What JS does with is a bit different to that.
You can equate it to something like (for every element created):
element.addEventListener('click', function() {
switch(typeof element.onclick) {
case 'string':eval(element.onclick);break;
case 'function':element.onclick();break;
}
});
The actual implementation details will likely differ with a range of subtle variations making the two slightly different in some cases but that's the gist of it.
It's arguably a compatibility hack that you can pin a function to an on attribute since by default attributes are all strings.

You should also consider EventDelegation for that!
For that reason I prefer the addEventListener and foremost using it carefully and consciously!
FACTS:
EventListeners are heavy .... (memory allocation at the client side)
The Events propagate IN and then OUT again in relation to the DOM
tree. Also known as trickling-in and bubbling-out , give it a read
in case you don't know.
So imagine an easy example:
a simple button INSIDE a div INSIDE body ...
if you click on the button, an Event will ANYWAY
trickle in to BUTTON and then OUT again, like this:
window-document-div-button-div-document-window
In the browser background (lets say the software periphery of the JS engine) the browser can ONLY possibly react to a click, if it checks for each click done where it was targeted.
And to make sure that each possible event listener on the way is triggered, it kinda has to send the "click event signal" all the way from document level down into the element ... and back out again.
This behavior can then made use of by attaching EventListeners using e.g.:
document.getElementById("exampleID").addEventListener("click",(event) => {doThis}, true/false);
Just note for reference that the true/false as the last argument of the addEventListener method controls the behavior in terms of when is the event recognized - when trickling in or when bubbling out.
TRUE means, the event is recognized while trickling-in
FALSE means, the event is recognized on its way bubbling out
Implementing the following 2 helpful concepts also turns out much more intuitive using the above stated approach to handle:
You can also use event.stopPropagation() within the function
(example ref. "doThis") to prevents further propagation of the
current event in the capturing and bubbling phases. It does not,
however, prevent any default behaviors from occurring; for instance,
clicks on links are still processed.
If you want to stop those behaviors, you could use
event.preventDefault() within the function (example ref.
"doThis"). With that you could for example tell the Browser that if
the event does not get explicitly handled, its default action should
not be taken as it normally would be.
Also just note here for reference again: the last argument of the addEventListener method (true/false) also controls at which phase (trickling-in TRUE or bubbling out FALSE) the eventual effect of ".stopPropagation()" kicks in.
So ... in case you apply an EventListener with flag TRUE to an element, and combine that with the .stopPropagation() method, the event would not even get through to potential inner children of the element
To wrap it up:
If you use the onClick variant in HTML ... there are 2 downsides for me:
With addEventListener, you can attach multiple onClick-events to the same, respectively one single element, but thats not possible using onClick (at least thats what I strongly believe up to now, correct me if I am wrong).
Also the following aspect is truly remarkable here ... especially the code maintenance part (didn't elaborate on this so far):
In regards to event delegation, it really boils down to this. If some
other JavaScript code needs to respond to a click event, using
addEventListener ensures you both can respond to it. If you both try
using onclick, then one stomps on the other. You both can't respond if
you want an onclick on the same element. Furthermore, you want to keep your behavior as separate as you can from the HTML in case you need to change it later. It would suck to have 50 HTML files to update instead of one JavaScript file.
(credit to Greg Burghardt, addEventListener vs onclick with regards to event delegation )
This is also known by the term "Unobtrusive JavaScript" ... give it a read!

According to MDN, the difference is as below:
addEventListener:
The EventTarget.addEventListener() method adds the specified
EventListener-compatible object to the list of event listeners for the
specified event type on the EventTarget on which it's called. The
event target may be an Element in a document, the Document itself, a
Window, or any other object that supports events (such as
XMLHttpRequest).
onclick:
The onclick property returns the click event handler code on the
current element. When using the click event to trigger an action, also
consider adding this same action to the keydown event, to allow the
use of that same action by people who don't use a mouse or a touch
screen. Syntax element.onclick = functionRef; where functionRef is a
function - often a name of a function declared elsewhere or a function
expression. See "JavaScript Guide:Functions" for details.
There is also a syntax difference in use as you see in the below codes:
addEventListener:
// Function to change the content of t2
function modifyText() {
var t2 = document.getElementById("t2");
if (t2.firstChild.nodeValue == "three") {
t2.firstChild.nodeValue = "two";
} else {
t2.firstChild.nodeValue = "three";
}
}
// add event listener to table
var el = document.getElementById("outside");
el.addEventListener("click", modifyText, false);
onclick:
function initElement() {
var p = document.getElementById("foo");
// NOTE: showAlert(); or showAlert(param); will NOT work here.
// Must be a reference to a function name, not a function call.
p.onclick = showAlert;
};
function showAlert(event) {
alert("onclick Event detected!");
}

I guess Chris Baker pretty much summed it up in an excellent answer but I would like to add to that with addEventListener() you can also use options parameter which gives you more control over your events. For example - If you just want to run your event once then you can use { once: true } as an option parameter when adding your event to only call it once.
function greet() {
console.log("Hello");
}
document.querySelector("button").addEventListener('click', greet, { once: true })
The above function will only print "Hello" once.
Also, if you want to cleanup your events then there is also the option to removeEventListener(). Although there are advantages of using addEventListener() but you should still be careful if your targeting audience is using Internet Explorer then this method might not work in all situation. You can also read about addEventListener on MDN, they gave quite a good explanation on how to use them.

If you are not too worried about browser support, there is a way to rebind the 'this' reference in the function called by the event. It will normally point to the element that generated the event when the function is executed, which is not always what you want. The tricky part is to at the same time be able to remove the very same event listener, as shown in this example: http://jsfiddle.net/roenbaeck/vBYu3/
/*
Testing that the function returned from bind is rereferenceable,
such that it can be added and removed as an event listener.
*/
function MyImportantCalloutToYou(message, otherMessage) {
// the following is necessary as calling bind again does
// not return the same function, so instead we replace the
// original function with the one bound to this instance
this.swap = this.swap.bind(this);
this.element = document.createElement('div');
this.element.addEventListener('click', this.swap, false);
document.body.appendChild(this.element);
}
MyImportantCalloutToYou.prototype = {
element: null,
swap: function() {
// now this function can be properly removed
this.element.removeEventListener('click', this.swap, false);
}
}
The code above works well in Chrome, and there's probably some shim around making "bind" compatible with other browsers.

Using inline handlers is incompatible with Content Security Policy so the addEventListener approach is more secure from that point of view. Of course you can enable the inline handlers with unsafe-inline but, as the name suggests, it's not safe as it brings back the whole hordes of JavaScript exploits that CSP prevents.

It should also be possible to either extend the listener by prototyping it (if we have a reference to it and its not an anonymous function) -or make the onclick call a call to a function library (a function calling other functions).
Like:
elm.onclick = myFunctionList;
function myFunctionList(){
myFunc1();
myFunc2();
}
This means we never have to change the onclick call just alter the function myFunctionList() to do whatever we want, but this leaves us without control of bubbling/catching phases so should be avoided for newer browsers.

addEventListener lets you set multiple handlers, but isn't supported in IE8 or lower.
IE does have attachEvent, but it's not exactly the same.

The context referenced by 'this' keyword in JavasSript is different.
look at the following code:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
</head>
<body>
<input id="btnSubmit" type="button" value="Submit" />
<script>
function disable() {
this.disabled = true;
}
var btnSubmit = document.getElementById('btnSubmit');
btnSubmit.onclick = disable();
//btnSubmit.addEventListener('click', disable, false);
</script>
</body>
</html>
What it does is really simple. when you click the button, the button will be disabled automatically.
First when you try to hook up the events in this way button.onclick = function(),
onclick event will be triggered by clicking the button, however, the button will not be disabled because there's no explicit binding between button.onclick and onclick event handler. If you debug see the 'this' object, you can see it refers to 'window' object.
Secondly, if you comment btnSubmit.onclick = disable(); and uncomment
//btnSubmit.addEventListener('click', disable, false); you can see that the button is disabled because with this way there's explicit binding between button.onclick event and onclick event handler. If you debug into disable function, you can see 'this' refers to the button control rather than the window.
This is something I don't like about JavaScript which is inconsistency.
Btw, if you are using jQuery($('#btnSubmit').on('click', disable);), it uses explicit binding.

onclick is basically an addEventListener that specifically performs a function when the element is clicked. So, useful when you have a button that does simple operations, like a calculator button. addEventlistener can be used for a multitude of things like performing an operation when DOM or all content is loaded, akin to window.onload but with more control.
Note, You can actually use more than one event with inline, or at least by using onclick by seperating each function with a semi-colon, like this....
I wouldn't write a function with inline, as you could potentially have problems later and it would be messy imo. Just use it to call functions already done in your script file.
Which one you use I suppose would depend on what you want. addEventListener for complex operations and onclick for simple. I've seen some projects not attach a specific one to elements and would instead implement a more global eventlistener that would determine if a tap was on a button and perform certain tasks depending on what was pressed. Imo that could potentially lead to problems I'd think, and albeit small, probably, a resource waste if that eventlistener had to handle each and every click

in my Visual Studio Code, addEventListener has Real Intellisense on event
but onclick does not, only fake ones

let element = document.queryselector('id or classname');
element.addeventlistiner('click',()=>{
do work
})
<button onclick="click()">click</click>`
function click(){
do work
};

Related

How to prevent event handler attached in one userscript from interfering with another?

I have installed two separate userscripts, each requiring to invoke some code with document.body.onkeydown. However, I've noticed that with both userscripts enabled, only the latter event handler gets called.
Apparently, both userscripts are sharing the same DOM. This is contrary to my experience with Chrome extensions, where each Chrome extension has its own sandbox.
Either way, now how do I to fix this problem? I want both handlers to fire, and remain separate from each other.
I am executing my userscripts inside an IIFE with use strict mode enabled.
Using document.body.keydown will set the callback to the keydown event. Setting it again will replace the old one. Hence the latter script's event callback gets fired.
Instead use, document.body.addEventListener(<callback>) in both so, both the events will present.
In the below example, first keydown will get overridden by the second one. The addEventListener will append an listener to the keydown event. So on pressing a only 3rd event fired. On pressing b, both 2nd and 3rd are fired.
This is because the events added via the older method is added as like attribute values. Like,
<button id="show" onclick="show()">Click</button>
Hence, it got replaced.
The addEventListener adds the listener to the list of EventListners of the DOM Object.
In the example I replaced the onclick attribute with the function hide via the older method, hence it calls only the hide method.
For more info, please refer MDN Docs
document.body.onkeydown = function(event){if(event.key=="a")console.log("keydown")};
document.body.onkeydown = function(event){if(event.key=="b")console.log("b keydown")};
document.body.addEventListener("keydown",function(){console.log("addEventListener")})
function show(){console.log("show")}
function hide(){console.log("hide")}
var element = document.getElementById("show");
element.onclick=hide;
<button id="show" onclick="show()">Click</button>
You can change them to use
document.body.addEventListener("keydown", function(){ ... })
If they use the 'this' set in the onkeydown approach, you may need to make sure that is set correctly
document.body.addEventListener("keydown", (function(){ ... }).bind(document.body))

Which is better and why ? element.onclick = function() Versus AddEventListener() [duplicate]

What's the difference between addEventListener and onclick?
var h = document.getElementById("a");
h.onclick = dothing1;
h.addEventListener("click", dothing2);
The code above resides together in a separate .js file, and they both work perfectly.
Both are correct, but none of them are "best" per se, and there may be a reason the developer chose to use both approaches.
Event Listeners (addEventListener and IE's attachEvent)
Earlier versions of Internet Explorer implement JavaScript differently from pretty much every other browser. With versions less than 9, you use the attachEvent[doc] method, like this:
element.attachEvent('onclick', function() { /* do stuff here*/ });
In most other browsers (including IE 9 and above), you use addEventListener[doc], like this:
element.addEventListener('click', function() { /* do stuff here*/ }, false);
Using this approach (DOM Level 2 events), you can attach a theoretically unlimited number of events to any single element. The only practical limitation is client-side memory and other performance concerns, which are different for each browser.
The examples above represent using an anonymous function[doc]. You can also add an event listener using a function reference[doc] or a closure[doc]:
var myFunctionReference = function() { /* do stuff here*/ }
element.attachEvent('onclick', myFunctionReference);
element.addEventListener('click', myFunctionReference , false);
Another important feature of addEventListener is the final parameter, which controls how the listener reacts to bubbling events[doc]. I've been passing false in the examples, which is standard for probably 95% of use cases. There is no equivalent argument for attachEvent, or when using inline events.
Inline events (HTML onclick="" property and element.onclick)
In all browsers that support javascript, you can put an event listener inline, meaning right in the HTML code. You've probably seen this:
<a id="testing" href="#" onclick="alert('did stuff inline');">Click me</a>
Most experienced developers shun this method, but it does get the job done; it is simple and direct. You may not use closures or anonymous functions here (though the handler itself is an anonymous function of sorts), and your control of scope is limited.
The other method you mention:
element.onclick = function () { /*do stuff here */ };
... is the equivalent of inline javascript except that you have more control of the scope (since you're writing a script rather than HTML) and can use anonymous functions, function references, and/or closures.
The significant drawback with inline events is that unlike event listeners described above, you may only have one inline event assigned. Inline events are stored as an attribute/property of the element[doc], meaning that it can be overwritten.
Using the example <a> from the HTML above:
var element = document.getElementById('testing');
element.onclick = function () { alert('did stuff #1'); };
element.onclick = function () { alert('did stuff #2'); };
... when you clicked the element, you'd only see "Did stuff #2" - you overwrote the first assigned of the onclick property with the second value, and you overwrote the original inline HTML onclick property too. Check it out here: http://jsfiddle.net/jpgah/.
Broadly speaking, do not use inline events. There may be specific use cases for it, but if you are not 100% sure you have that use case, then you do not and should not use inline events.
Modern Javascript (Angular and the like)
Since this answer was originally posted, javascript frameworks like Angular have become far more popular. You will see code like this in an Angular template:
<button (click)="doSomething()">Do Something</button>
This looks like an inline event, but it isn't. This type of template will be transpiled into more complex code which uses event listeners behind the scenes. Everything I've written about events here still applies, but you are removed from the nitty gritty by at least one layer. You should understand the nuts and bolts, but if your modern JS framework best practices involve writing this kind of code in a template, don't feel like you're using an inline event -- you aren't.
Which is Best?
The question is a matter of browser compatibility and necessity. Do you need to attach more than one event to an element? Will you in the future? Odds are, you will. attachEvent and addEventListener are necessary. If not, an inline event may seem like they'd do the trick, but you're much better served preparing for a future that, though it may seem unlikely, is predictable at least. There is a chance you'll have to move to JS-based event listeners, so you may as well just start there. Don't use inline events.
jQuery and other javascript frameworks encapsulate the different browser implementations of DOM level 2 events in generic models so you can write cross-browser compliant code without having to worry about IE's history as a rebel. Same code with jQuery, all cross-browser and ready to rock:
$(element).on('click', function () { /* do stuff */ });
Don't run out and get a framework just for this one thing, though. You can easily roll your own little utility to take care of the older browsers:
function addEvent(element, evnt, funct){
if (element.attachEvent)
return element.attachEvent('on'+evnt, funct);
else
return element.addEventListener(evnt, funct, false);
}
// example
addEvent(
document.getElementById('myElement'),
'click',
function () { alert('hi!'); }
);
Try it: http://jsfiddle.net/bmArj/
Taking all of that into consideration, unless the script you're looking at took the browser differences into account some other way (in code not shown in your question), the part using addEventListener would not work in IE versions less than 9.
Documentation and Related Reading
W3 HTML specification, element Event Handler Attributes
element.addEventListener on MDN
element.attachEvent on MSDN
Jquery.on
quirksmode blog "Introduction to Events"
CDN-hosted javascript libraries at Google
The difference you could see if you had another couple of functions:
var h = document.getElementById('a');
h.onclick = doThing_1;
h.onclick = doThing_2;
h.addEventListener('click', doThing_3);
h.addEventListener('click', doThing_4);
Functions 2, 3 and 4 work, but 1 does not. This is because addEventListener does not overwrite existing event handlers, whereas onclick overrides any existing onclick = fn event handlers.
The other significant difference, of course, is that onclick will always work, whereas addEventListener does not work in Internet Explorer before version 9. You can use the analogous attachEvent (which has slightly different syntax) in IE <9.
In this answer I will describe the three methods of defining DOM event handlers.
element.addEventListener()
Code example:
const element = document.querySelector('a');
element.addEventListener('click', event => event.preventDefault(), true);
Try clicking this link.
element.addEventListener() has multiple advantages:
Allows you to register unlimited events handlers and remove them with element.removeEventListener().
Has useCapture parameter, which indicates whether you'd like to handle event in its capturing or bubbling phase. See: Unable to understand useCapture attribute in addEventListener.
Cares about semantics. Basically, it makes registering event handlers more explicit. For a beginner, a function call makes it obvious that something happens, whereas assigning event to some property of DOM element is at least not intuitive.
Allows you to separate document structure (HTML) and logic (JavaScript). In tiny web applications it may not seem to matter, but it does matter with any bigger project. It's way much easier to maintain a project which separates structure and logic than a project which doesn't.
Eliminates confusion with correct event names. Due to using inline event listeners or assigning event listeners to .onevent properties of DOM elements, lots of inexperienced JavaScript programmers thinks that the event name is for example onclick or onload. on is not a part of event name. Correct event names are click and load, and that's how event names are passed to .addEventListener().
Works in almost all browser. If you still have to support IE <= 8, you can use a polyfill from MDN.
element.onevent = function() {} (e.g. onclick, onload)
Code example:
const element = document.querySelector('a');
element.onclick = event => event.preventDefault();
Try clicking this link.
This was a way to register event handlers in DOM 0. It's now discouraged, because it:
Allows you to register only one event handler. Also removing the assigned handler is not intuitive, because to remove event handler assigned using this method, you have to revert onevent property back to its initial state (i.e. null).
Doesn't respond to errors appropriately. For example, if you by mistake assign a string to window.onload, for example: window.onload = "test";, it won't throw any errors. Your code wouldn't work and it would be really hard to find out why. .addEventListener() however, would throw error (at least in Firefox): TypeError: Argument 2 of EventTarget.addEventListener is not an object.
Doesn't provide a way to choose if you want to handle event in its capturing or bubbling phase.
Inline event handlers (onevent HTML attribute)
Code example:
Try clicking this link.
Similarly to element.onevent, it's now discouraged. Besides the issues that element.onevent has, it:
Is a potential security issue, because it makes XSS much more harmful. Nowadays websites should send proper Content-Security-Policy HTTP header to block inline scripts and allow external scripts only from trusted domains. See How does Content Security Policy work?
Doesn't separate document structure and logic.
If you generate your page with a server-side script, and for example you generate a hundred links, each with the same inline event handler, your code would be much longer than if the event handler was defined only once. That means the client would have to download more content, and in result your website would be slower.
See also
EventTarget.addEventListener() documentation (MDN)
EventTarget.removeEventListener() documentation (MDN)
onclick vs addEventListener
dom-events tag wiki
While onclick works in all browsers, addEventListener does not work in older versions of Internet Explorer, which uses attachEvent instead.
The downside of onclick is that there can only be one event handler, while the other two will fire all registered callbacks.
Summary:
addEventListener can add multiple events, whereas with onclick this cannot be done.
onclick can be added as an HTML attribute, whereas an addEventListener can only be added within <script> elements.
addEventListener can take a third argument which can stop the event propagation.
Both can be used to handle events. However, addEventListener should be the preferred choice since it can do everything onclick does and more. Don't use inline onclick as HTML attributes as this mixes up the javascript and the HTML which is a bad practice. It makes the code less maintainable.
As far as I know, the DOM "load" event still does only work very limited. That means it'll only fire for the window object, images and <script> elements for instance. The same goes for the direct onload assignment. There is no technical difference between those two. Probably .onload = has a better cross-browser availabilty.
However, you cannot assign a load event to a <div> or <span> element or whatnot.
An element can have only one event handler attached per event type, but can have multiple event listeners.
So, how does it look in action?
Only the last event handler assigned gets run:
const button = document.querySelector(".btn")
button.onclick = () => {
console.log("Hello World");
};
button.onclick = () => {
console.log("How are you?");
};
button.click() // "How are you?"
All event listeners will be triggered:
const button = document.querySelector(".btn")
button.addEventListener("click", event => {
console.log("Hello World");
})
button.addEventListener("click", event => {
console.log("How are you?");
})
button.click()
// "Hello World"
// "How are you?"
IE Note: attachEvent is no longer supported. Starting with IE 11, use addEventListener: docs.
One detail hasn't been noted yet: modern desktop browsers consider different button presses to be "clicks" for AddEventListener('click' and onclick by default.
On Chrome 42 and IE11, both onclick and AddEventListener click fire on left and middle click.
On Firefox 38, onclick fires only on left click, but AddEventListener click fires on left, middle and right clicks.
Also, middle-click behavior is very inconsistent across browsers when scroll cursors are involved:
On Firefox, middle-click events always fire.
On Chrome, they won't fire if the middleclick opens or closes a scroll cursor.
On IE, they fire when scroll cursor closes, but not when it opens.
It is also worth noting that "click" events for any keyboard-selectable HTML element such as input also fire on space or enter when the element is selected.
element.onclick = function() { /* do stuff */ }
element.addEventListener('click', function(){ /* do stuff */ },false);
They apparently do the same thing: listen for the click event and execute a callback function. Nevertheless, they’re not equivalent. If you ever need to choose between the two, this could help you to figure out which one is the best for you.
The main difference is that onclick is just a property, and like all object properties, if you write on more than once, it will be overwritten. With addEventListener() instead, we can simply bind an event handler to the element, and we can call it each time we need it without being worried of any overwritten properties.
Example is shown here,
Try it: https://jsfiddle.net/fjets5z4/5/
In first place I was tempted to keep using onclick, because it’s shorter and looks simpler… and in fact it is. But I don’t recommend using it anymore. It’s just like using inline JavaScript. Using something like – that’s inline JavaScript – is highly discouraged nowadays (inline CSS is discouraged too, but that’s another topic).
However, the addEventListener() function, despite it’s the standard, just doesn’t work in old browsers (Internet Explorer below version 9), and this is another big difference. If you need to support these ancient browsers, you should follow the onclick way. But you could also use jQuery (or one of its alternatives): it basically simplifies your work and reduces the differences between browsers, therefore can save you a lot of time.
var clickEvent = document.getElementByID("onclick-eg");
var EventListener = document.getElementByID("addEventListener-eg");
clickEvent.onclick = function(){
window.alert("1 is not called")
}
clickEvent.onclick = function(){
window.alert("1 is not called, 2 is called")
}
EventListener.addEventListener("click",function(){
window.alert("1 is called")
})
EventListener.addEventListener("click",function(){
window.alert("2 is also called")
})
Javascript tends to blend everything into objects and that can make it confusing. All into one is the JavaScript way.
Essentially onclick is a HTML attribute. Conversely addEventListener is a method on the DOM object representing a HTML element.
In JavaScript objects, a method is merely a property that has a function as a value and that works against the object it is attached to (using this for example).
In JavaScript as HTML element represented by DOM will have it's attributes mapped onto its properties.
This is where people get confused because JavaScript melds everything into a single container or namespace with no layer of indirection.
In a normal OO layout (which does at least merge the namespace of properties/methods) you would might have something like:
domElement.addEventListener // Object(Method)
domElement.attributes.onload // Object(Property(Object(Property(String))))
There are variations like it could use a getter/setter for onload or HashMap for attributes but ultimately that's how it would look. JavaScript eliminated that layer of indirection at the expect of knowing what's what among other things. It merged domElement and attributes together.
Barring compatibility you should as a best practice use addEventListener. As other answers talk about the differences in that regard rather than the fundamental programmatic differences I will forgo it. Essentially, in an ideal world you're really only meant to use on* from HTML but in an even more ideal world you shouldn't be doing anything like that from HTML.
Why is it dominant today? It's quicker to write, easier to learn and tends to just work.
The whole point of onload in HTML is to give access to the addEventListener method or functionality in the first place. By using it in JS you're going through HTML when you could be applying it directly.
Hypothetically you can make your own attributes:
$('[myclick]').each(function(i, v) {
v.addEventListener('click', function() {
eval(v.myclick); // eval($(v).attr('myclick'));
});
});
What JS does with is a bit different to that.
You can equate it to something like (for every element created):
element.addEventListener('click', function() {
switch(typeof element.onclick) {
case 'string':eval(element.onclick);break;
case 'function':element.onclick();break;
}
});
The actual implementation details will likely differ with a range of subtle variations making the two slightly different in some cases but that's the gist of it.
It's arguably a compatibility hack that you can pin a function to an on attribute since by default attributes are all strings.
You should also consider EventDelegation for that!
For that reason I prefer the addEventListener and foremost using it carefully and consciously!
FACTS:
EventListeners are heavy .... (memory allocation at the client side)
The Events propagate IN and then OUT again in relation to the DOM
tree. Also known as trickling-in and bubbling-out , give it a read
in case you don't know.
So imagine an easy example:
a simple button INSIDE a div INSIDE body ...
if you click on the button, an Event will ANYWAY
trickle in to BUTTON and then OUT again, like this:
window-document-div-button-div-document-window
In the browser background (lets say the software periphery of the JS engine) the browser can ONLY possibly react to a click, if it checks for each click done where it was targeted.
And to make sure that each possible event listener on the way is triggered, it kinda has to send the "click event signal" all the way from document level down into the element ... and back out again.
This behavior can then made use of by attaching EventListeners using e.g.:
document.getElementById("exampleID").addEventListener("click",(event) => {doThis}, true/false);
Just note for reference that the true/false as the last argument of the addEventListener method controls the behavior in terms of when is the event recognized - when trickling in or when bubbling out.
TRUE means, the event is recognized while trickling-in
FALSE means, the event is recognized on its way bubbling out
Implementing the following 2 helpful concepts also turns out much more intuitive using the above stated approach to handle:
You can also use event.stopPropagation() within the function
(example ref. "doThis") to prevents further propagation of the
current event in the capturing and bubbling phases. It does not,
however, prevent any default behaviors from occurring; for instance,
clicks on links are still processed.
If you want to stop those behaviors, you could use
event.preventDefault() within the function (example ref.
"doThis"). With that you could for example tell the Browser that if
the event does not get explicitly handled, its default action should
not be taken as it normally would be.
Also just note here for reference again: the last argument of the addEventListener method (true/false) also controls at which phase (trickling-in TRUE or bubbling out FALSE) the eventual effect of ".stopPropagation()" kicks in.
So ... in case you apply an EventListener with flag TRUE to an element, and combine that with the .stopPropagation() method, the event would not even get through to potential inner children of the element
To wrap it up:
If you use the onClick variant in HTML ... there are 2 downsides for me:
With addEventListener, you can attach multiple onClick-events to the same, respectively one single element, but thats not possible using onClick (at least thats what I strongly believe up to now, correct me if I am wrong).
Also the following aspect is truly remarkable here ... especially the code maintenance part (didn't elaborate on this so far):
In regards to event delegation, it really boils down to this. If some
other JavaScript code needs to respond to a click event, using
addEventListener ensures you both can respond to it. If you both try
using onclick, then one stomps on the other. You both can't respond if
you want an onclick on the same element. Furthermore, you want to keep your behavior as separate as you can from the HTML in case you need to change it later. It would suck to have 50 HTML files to update instead of one JavaScript file.
(credit to Greg Burghardt, addEventListener vs onclick with regards to event delegation )
This is also known by the term "Unobtrusive JavaScript" ... give it a read!
According to MDN, the difference is as below:
addEventListener:
The EventTarget.addEventListener() method adds the specified
EventListener-compatible object to the list of event listeners for the
specified event type on the EventTarget on which it's called. The
event target may be an Element in a document, the Document itself, a
Window, or any other object that supports events (such as
XMLHttpRequest).
onclick:
The onclick property returns the click event handler code on the
current element. When using the click event to trigger an action, also
consider adding this same action to the keydown event, to allow the
use of that same action by people who don't use a mouse or a touch
screen. Syntax element.onclick = functionRef; where functionRef is a
function - often a name of a function declared elsewhere or a function
expression. See "JavaScript Guide:Functions" for details.
There is also a syntax difference in use as you see in the below codes:
addEventListener:
// Function to change the content of t2
function modifyText() {
var t2 = document.getElementById("t2");
if (t2.firstChild.nodeValue == "three") {
t2.firstChild.nodeValue = "two";
} else {
t2.firstChild.nodeValue = "three";
}
}
// add event listener to table
var el = document.getElementById("outside");
el.addEventListener("click", modifyText, false);
onclick:
function initElement() {
var p = document.getElementById("foo");
// NOTE: showAlert(); or showAlert(param); will NOT work here.
// Must be a reference to a function name, not a function call.
p.onclick = showAlert;
};
function showAlert(event) {
alert("onclick Event detected!");
}
I guess Chris Baker pretty much summed it up in an excellent answer but I would like to add to that with addEventListener() you can also use options parameter which gives you more control over your events. For example - If you just want to run your event once then you can use { once: true } as an option parameter when adding your event to only call it once.
function greet() {
console.log("Hello");
}
document.querySelector("button").addEventListener('click', greet, { once: true })
The above function will only print "Hello" once.
Also, if you want to cleanup your events then there is also the option to removeEventListener(). Although there are advantages of using addEventListener() but you should still be careful if your targeting audience is using Internet Explorer then this method might not work in all situation. You can also read about addEventListener on MDN, they gave quite a good explanation on how to use them.
If you are not too worried about browser support, there is a way to rebind the 'this' reference in the function called by the event. It will normally point to the element that generated the event when the function is executed, which is not always what you want. The tricky part is to at the same time be able to remove the very same event listener, as shown in this example: http://jsfiddle.net/roenbaeck/vBYu3/
/*
Testing that the function returned from bind is rereferenceable,
such that it can be added and removed as an event listener.
*/
function MyImportantCalloutToYou(message, otherMessage) {
// the following is necessary as calling bind again does
// not return the same function, so instead we replace the
// original function with the one bound to this instance
this.swap = this.swap.bind(this);
this.element = document.createElement('div');
this.element.addEventListener('click', this.swap, false);
document.body.appendChild(this.element);
}
MyImportantCalloutToYou.prototype = {
element: null,
swap: function() {
// now this function can be properly removed
this.element.removeEventListener('click', this.swap, false);
}
}
The code above works well in Chrome, and there's probably some shim around making "bind" compatible with other browsers.
Using inline handlers is incompatible with Content Security Policy so the addEventListener approach is more secure from that point of view. Of course you can enable the inline handlers with unsafe-inline but, as the name suggests, it's not safe as it brings back the whole hordes of JavaScript exploits that CSP prevents.
It should also be possible to either extend the listener by prototyping it (if we have a reference to it and its not an anonymous function) -or make the onclick call a call to a function library (a function calling other functions).
Like:
elm.onclick = myFunctionList;
function myFunctionList(){
myFunc1();
myFunc2();
}
This means we never have to change the onclick call just alter the function myFunctionList() to do whatever we want, but this leaves us without control of bubbling/catching phases so should be avoided for newer browsers.
addEventListener lets you set multiple handlers, but isn't supported in IE8 or lower.
IE does have attachEvent, but it's not exactly the same.
The context referenced by 'this' keyword in JavasSript is different.
look at the following code:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
</head>
<body>
<input id="btnSubmit" type="button" value="Submit" />
<script>
function disable() {
this.disabled = true;
}
var btnSubmit = document.getElementById('btnSubmit');
btnSubmit.onclick = disable();
//btnSubmit.addEventListener('click', disable, false);
</script>
</body>
</html>
What it does is really simple. when you click the button, the button will be disabled automatically.
First when you try to hook up the events in this way button.onclick = function(),
onclick event will be triggered by clicking the button, however, the button will not be disabled because there's no explicit binding between button.onclick and onclick event handler. If you debug see the 'this' object, you can see it refers to 'window' object.
Secondly, if you comment btnSubmit.onclick = disable(); and uncomment
//btnSubmit.addEventListener('click', disable, false); you can see that the button is disabled because with this way there's explicit binding between button.onclick event and onclick event handler. If you debug into disable function, you can see 'this' refers to the button control rather than the window.
This is something I don't like about JavaScript which is inconsistency.
Btw, if you are using jQuery($('#btnSubmit').on('click', disable);), it uses explicit binding.
onclick is basically an addEventListener that specifically performs a function when the element is clicked. So, useful when you have a button that does simple operations, like a calculator button. addEventlistener can be used for a multitude of things like performing an operation when DOM or all content is loaded, akin to window.onload but with more control.
Note, You can actually use more than one event with inline, or at least by using onclick by seperating each function with a semi-colon, like this....
I wouldn't write a function with inline, as you could potentially have problems later and it would be messy imo. Just use it to call functions already done in your script file.
Which one you use I suppose would depend on what you want. addEventListener for complex operations and onclick for simple. I've seen some projects not attach a specific one to elements and would instead implement a more global eventlistener that would determine if a tap was on a button and perform certain tasks depending on what was pressed. Imo that could potentially lead to problems I'd think, and albeit small, probably, a resource waste if that eventlistener had to handle each and every click
in my Visual Studio Code, addEventListener has Real Intellisense on event
but onclick does not, only fake ones
let element = document.queryselector('id or classname');
element.addeventlistiner('click',()=>{
do work
})
<button onclick="click()">click</click>`
function click(){
do work
};

element.onload vs element.addEventListener("load",callbak,false) [duplicate]

What's the difference between addEventListener and onclick?
var h = document.getElementById("a");
h.onclick = dothing1;
h.addEventListener("click", dothing2);
The code above resides together in a separate .js file, and they both work perfectly.
Both are correct, but none of them are "best" per se, and there may be a reason the developer chose to use both approaches.
Event Listeners (addEventListener and IE's attachEvent)
Earlier versions of Internet Explorer implement JavaScript differently from pretty much every other browser. With versions less than 9, you use the attachEvent[doc] method, like this:
element.attachEvent('onclick', function() { /* do stuff here*/ });
In most other browsers (including IE 9 and above), you use addEventListener[doc], like this:
element.addEventListener('click', function() { /* do stuff here*/ }, false);
Using this approach (DOM Level 2 events), you can attach a theoretically unlimited number of events to any single element. The only practical limitation is client-side memory and other performance concerns, which are different for each browser.
The examples above represent using an anonymous function[doc]. You can also add an event listener using a function reference[doc] or a closure[doc]:
var myFunctionReference = function() { /* do stuff here*/ }
element.attachEvent('onclick', myFunctionReference);
element.addEventListener('click', myFunctionReference , false);
Another important feature of addEventListener is the final parameter, which controls how the listener reacts to bubbling events[doc]. I've been passing false in the examples, which is standard for probably 95% of use cases. There is no equivalent argument for attachEvent, or when using inline events.
Inline events (HTML onclick="" property and element.onclick)
In all browsers that support javascript, you can put an event listener inline, meaning right in the HTML code. You've probably seen this:
<a id="testing" href="#" onclick="alert('did stuff inline');">Click me</a>
Most experienced developers shun this method, but it does get the job done; it is simple and direct. You may not use closures or anonymous functions here (though the handler itself is an anonymous function of sorts), and your control of scope is limited.
The other method you mention:
element.onclick = function () { /*do stuff here */ };
... is the equivalent of inline javascript except that you have more control of the scope (since you're writing a script rather than HTML) and can use anonymous functions, function references, and/or closures.
The significant drawback with inline events is that unlike event listeners described above, you may only have one inline event assigned. Inline events are stored as an attribute/property of the element[doc], meaning that it can be overwritten.
Using the example <a> from the HTML above:
var element = document.getElementById('testing');
element.onclick = function () { alert('did stuff #1'); };
element.onclick = function () { alert('did stuff #2'); };
... when you clicked the element, you'd only see "Did stuff #2" - you overwrote the first assigned of the onclick property with the second value, and you overwrote the original inline HTML onclick property too. Check it out here: http://jsfiddle.net/jpgah/.
Broadly speaking, do not use inline events. There may be specific use cases for it, but if you are not 100% sure you have that use case, then you do not and should not use inline events.
Modern Javascript (Angular and the like)
Since this answer was originally posted, javascript frameworks like Angular have become far more popular. You will see code like this in an Angular template:
<button (click)="doSomething()">Do Something</button>
This looks like an inline event, but it isn't. This type of template will be transpiled into more complex code which uses event listeners behind the scenes. Everything I've written about events here still applies, but you are removed from the nitty gritty by at least one layer. You should understand the nuts and bolts, but if your modern JS framework best practices involve writing this kind of code in a template, don't feel like you're using an inline event -- you aren't.
Which is Best?
The question is a matter of browser compatibility and necessity. Do you need to attach more than one event to an element? Will you in the future? Odds are, you will. attachEvent and addEventListener are necessary. If not, an inline event may seem like they'd do the trick, but you're much better served preparing for a future that, though it may seem unlikely, is predictable at least. There is a chance you'll have to move to JS-based event listeners, so you may as well just start there. Don't use inline events.
jQuery and other javascript frameworks encapsulate the different browser implementations of DOM level 2 events in generic models so you can write cross-browser compliant code without having to worry about IE's history as a rebel. Same code with jQuery, all cross-browser and ready to rock:
$(element).on('click', function () { /* do stuff */ });
Don't run out and get a framework just for this one thing, though. You can easily roll your own little utility to take care of the older browsers:
function addEvent(element, evnt, funct){
if (element.attachEvent)
return element.attachEvent('on'+evnt, funct);
else
return element.addEventListener(evnt, funct, false);
}
// example
addEvent(
document.getElementById('myElement'),
'click',
function () { alert('hi!'); }
);
Try it: http://jsfiddle.net/bmArj/
Taking all of that into consideration, unless the script you're looking at took the browser differences into account some other way (in code not shown in your question), the part using addEventListener would not work in IE versions less than 9.
Documentation and Related Reading
W3 HTML specification, element Event Handler Attributes
element.addEventListener on MDN
element.attachEvent on MSDN
Jquery.on
quirksmode blog "Introduction to Events"
CDN-hosted javascript libraries at Google
The difference you could see if you had another couple of functions:
var h = document.getElementById('a');
h.onclick = doThing_1;
h.onclick = doThing_2;
h.addEventListener('click', doThing_3);
h.addEventListener('click', doThing_4);
Functions 2, 3 and 4 work, but 1 does not. This is because addEventListener does not overwrite existing event handlers, whereas onclick overrides any existing onclick = fn event handlers.
The other significant difference, of course, is that onclick will always work, whereas addEventListener does not work in Internet Explorer before version 9. You can use the analogous attachEvent (which has slightly different syntax) in IE <9.
In this answer I will describe the three methods of defining DOM event handlers.
element.addEventListener()
Code example:
const element = document.querySelector('a');
element.addEventListener('click', event => event.preventDefault(), true);
Try clicking this link.
element.addEventListener() has multiple advantages:
Allows you to register unlimited events handlers and remove them with element.removeEventListener().
Has useCapture parameter, which indicates whether you'd like to handle event in its capturing or bubbling phase. See: Unable to understand useCapture attribute in addEventListener.
Cares about semantics. Basically, it makes registering event handlers more explicit. For a beginner, a function call makes it obvious that something happens, whereas assigning event to some property of DOM element is at least not intuitive.
Allows you to separate document structure (HTML) and logic (JavaScript). In tiny web applications it may not seem to matter, but it does matter with any bigger project. It's way much easier to maintain a project which separates structure and logic than a project which doesn't.
Eliminates confusion with correct event names. Due to using inline event listeners or assigning event listeners to .onevent properties of DOM elements, lots of inexperienced JavaScript programmers thinks that the event name is for example onclick or onload. on is not a part of event name. Correct event names are click and load, and that's how event names are passed to .addEventListener().
Works in almost all browser. If you still have to support IE <= 8, you can use a polyfill from MDN.
element.onevent = function() {} (e.g. onclick, onload)
Code example:
const element = document.querySelector('a');
element.onclick = event => event.preventDefault();
Try clicking this link.
This was a way to register event handlers in DOM 0. It's now discouraged, because it:
Allows you to register only one event handler. Also removing the assigned handler is not intuitive, because to remove event handler assigned using this method, you have to revert onevent property back to its initial state (i.e. null).
Doesn't respond to errors appropriately. For example, if you by mistake assign a string to window.onload, for example: window.onload = "test";, it won't throw any errors. Your code wouldn't work and it would be really hard to find out why. .addEventListener() however, would throw error (at least in Firefox): TypeError: Argument 2 of EventTarget.addEventListener is not an object.
Doesn't provide a way to choose if you want to handle event in its capturing or bubbling phase.
Inline event handlers (onevent HTML attribute)
Code example:
Try clicking this link.
Similarly to element.onevent, it's now discouraged. Besides the issues that element.onevent has, it:
Is a potential security issue, because it makes XSS much more harmful. Nowadays websites should send proper Content-Security-Policy HTTP header to block inline scripts and allow external scripts only from trusted domains. See How does Content Security Policy work?
Doesn't separate document structure and logic.
If you generate your page with a server-side script, and for example you generate a hundred links, each with the same inline event handler, your code would be much longer than if the event handler was defined only once. That means the client would have to download more content, and in result your website would be slower.
See also
EventTarget.addEventListener() documentation (MDN)
EventTarget.removeEventListener() documentation (MDN)
onclick vs addEventListener
dom-events tag wiki
While onclick works in all browsers, addEventListener does not work in older versions of Internet Explorer, which uses attachEvent instead.
The downside of onclick is that there can only be one event handler, while the other two will fire all registered callbacks.
Summary:
addEventListener can add multiple events, whereas with onclick this cannot be done.
onclick can be added as an HTML attribute, whereas an addEventListener can only be added within <script> elements.
addEventListener can take a third argument which can stop the event propagation.
Both can be used to handle events. However, addEventListener should be the preferred choice since it can do everything onclick does and more. Don't use inline onclick as HTML attributes as this mixes up the javascript and the HTML which is a bad practice. It makes the code less maintainable.
As far as I know, the DOM "load" event still does only work very limited. That means it'll only fire for the window object, images and <script> elements for instance. The same goes for the direct onload assignment. There is no technical difference between those two. Probably .onload = has a better cross-browser availabilty.
However, you cannot assign a load event to a <div> or <span> element or whatnot.
An element can have only one event handler attached per event type, but can have multiple event listeners.
So, how does it look in action?
Only the last event handler assigned gets run:
const button = document.querySelector(".btn")
button.onclick = () => {
console.log("Hello World");
};
button.onclick = () => {
console.log("How are you?");
};
button.click() // "How are you?"
All event listeners will be triggered:
const button = document.querySelector(".btn")
button.addEventListener("click", event => {
console.log("Hello World");
})
button.addEventListener("click", event => {
console.log("How are you?");
})
button.click()
// "Hello World"
// "How are you?"
IE Note: attachEvent is no longer supported. Starting with IE 11, use addEventListener: docs.
One detail hasn't been noted yet: modern desktop browsers consider different button presses to be "clicks" for AddEventListener('click' and onclick by default.
On Chrome 42 and IE11, both onclick and AddEventListener click fire on left and middle click.
On Firefox 38, onclick fires only on left click, but AddEventListener click fires on left, middle and right clicks.
Also, middle-click behavior is very inconsistent across browsers when scroll cursors are involved:
On Firefox, middle-click events always fire.
On Chrome, they won't fire if the middleclick opens or closes a scroll cursor.
On IE, they fire when scroll cursor closes, but not when it opens.
It is also worth noting that "click" events for any keyboard-selectable HTML element such as input also fire on space or enter when the element is selected.
element.onclick = function() { /* do stuff */ }
element.addEventListener('click', function(){ /* do stuff */ },false);
They apparently do the same thing: listen for the click event and execute a callback function. Nevertheless, they’re not equivalent. If you ever need to choose between the two, this could help you to figure out which one is the best for you.
The main difference is that onclick is just a property, and like all object properties, if you write on more than once, it will be overwritten. With addEventListener() instead, we can simply bind an event handler to the element, and we can call it each time we need it without being worried of any overwritten properties.
Example is shown here,
Try it: https://jsfiddle.net/fjets5z4/5/
In first place I was tempted to keep using onclick, because it’s shorter and looks simpler… and in fact it is. But I don’t recommend using it anymore. It’s just like using inline JavaScript. Using something like – that’s inline JavaScript – is highly discouraged nowadays (inline CSS is discouraged too, but that’s another topic).
However, the addEventListener() function, despite it’s the standard, just doesn’t work in old browsers (Internet Explorer below version 9), and this is another big difference. If you need to support these ancient browsers, you should follow the onclick way. But you could also use jQuery (or one of its alternatives): it basically simplifies your work and reduces the differences between browsers, therefore can save you a lot of time.
var clickEvent = document.getElementByID("onclick-eg");
var EventListener = document.getElementByID("addEventListener-eg");
clickEvent.onclick = function(){
window.alert("1 is not called")
}
clickEvent.onclick = function(){
window.alert("1 is not called, 2 is called")
}
EventListener.addEventListener("click",function(){
window.alert("1 is called")
})
EventListener.addEventListener("click",function(){
window.alert("2 is also called")
})
Javascript tends to blend everything into objects and that can make it confusing. All into one is the JavaScript way.
Essentially onclick is a HTML attribute. Conversely addEventListener is a method on the DOM object representing a HTML element.
In JavaScript objects, a method is merely a property that has a function as a value and that works against the object it is attached to (using this for example).
In JavaScript as HTML element represented by DOM will have it's attributes mapped onto its properties.
This is where people get confused because JavaScript melds everything into a single container or namespace with no layer of indirection.
In a normal OO layout (which does at least merge the namespace of properties/methods) you would might have something like:
domElement.addEventListener // Object(Method)
domElement.attributes.onload // Object(Property(Object(Property(String))))
There are variations like it could use a getter/setter for onload or HashMap for attributes but ultimately that's how it would look. JavaScript eliminated that layer of indirection at the expect of knowing what's what among other things. It merged domElement and attributes together.
Barring compatibility you should as a best practice use addEventListener. As other answers talk about the differences in that regard rather than the fundamental programmatic differences I will forgo it. Essentially, in an ideal world you're really only meant to use on* from HTML but in an even more ideal world you shouldn't be doing anything like that from HTML.
Why is it dominant today? It's quicker to write, easier to learn and tends to just work.
The whole point of onload in HTML is to give access to the addEventListener method or functionality in the first place. By using it in JS you're going through HTML when you could be applying it directly.
Hypothetically you can make your own attributes:
$('[myclick]').each(function(i, v) {
v.addEventListener('click', function() {
eval(v.myclick); // eval($(v).attr('myclick'));
});
});
What JS does with is a bit different to that.
You can equate it to something like (for every element created):
element.addEventListener('click', function() {
switch(typeof element.onclick) {
case 'string':eval(element.onclick);break;
case 'function':element.onclick();break;
}
});
The actual implementation details will likely differ with a range of subtle variations making the two slightly different in some cases but that's the gist of it.
It's arguably a compatibility hack that you can pin a function to an on attribute since by default attributes are all strings.
You should also consider EventDelegation for that!
For that reason I prefer the addEventListener and foremost using it carefully and consciously!
FACTS:
EventListeners are heavy .... (memory allocation at the client side)
The Events propagate IN and then OUT again in relation to the DOM
tree. Also known as trickling-in and bubbling-out , give it a read
in case you don't know.
So imagine an easy example:
a simple button INSIDE a div INSIDE body ...
if you click on the button, an Event will ANYWAY
trickle in to BUTTON and then OUT again, like this:
window-document-div-button-div-document-window
In the browser background (lets say the software periphery of the JS engine) the browser can ONLY possibly react to a click, if it checks for each click done where it was targeted.
And to make sure that each possible event listener on the way is triggered, it kinda has to send the "click event signal" all the way from document level down into the element ... and back out again.
This behavior can then made use of by attaching EventListeners using e.g.:
document.getElementById("exampleID").addEventListener("click",(event) => {doThis}, true/false);
Just note for reference that the true/false as the last argument of the addEventListener method controls the behavior in terms of when is the event recognized - when trickling in or when bubbling out.
TRUE means, the event is recognized while trickling-in
FALSE means, the event is recognized on its way bubbling out
Implementing the following 2 helpful concepts also turns out much more intuitive using the above stated approach to handle:
You can also use event.stopPropagation() within the function
(example ref. "doThis") to prevents further propagation of the
current event in the capturing and bubbling phases. It does not,
however, prevent any default behaviors from occurring; for instance,
clicks on links are still processed.
If you want to stop those behaviors, you could use
event.preventDefault() within the function (example ref.
"doThis"). With that you could for example tell the Browser that if
the event does not get explicitly handled, its default action should
not be taken as it normally would be.
Also just note here for reference again: the last argument of the addEventListener method (true/false) also controls at which phase (trickling-in TRUE or bubbling out FALSE) the eventual effect of ".stopPropagation()" kicks in.
So ... in case you apply an EventListener with flag TRUE to an element, and combine that with the .stopPropagation() method, the event would not even get through to potential inner children of the element
To wrap it up:
If you use the onClick variant in HTML ... there are 2 downsides for me:
With addEventListener, you can attach multiple onClick-events to the same, respectively one single element, but thats not possible using onClick (at least thats what I strongly believe up to now, correct me if I am wrong).
Also the following aspect is truly remarkable here ... especially the code maintenance part (didn't elaborate on this so far):
In regards to event delegation, it really boils down to this. If some
other JavaScript code needs to respond to a click event, using
addEventListener ensures you both can respond to it. If you both try
using onclick, then one stomps on the other. You both can't respond if
you want an onclick on the same element. Furthermore, you want to keep your behavior as separate as you can from the HTML in case you need to change it later. It would suck to have 50 HTML files to update instead of one JavaScript file.
(credit to Greg Burghardt, addEventListener vs onclick with regards to event delegation )
This is also known by the term "Unobtrusive JavaScript" ... give it a read!
According to MDN, the difference is as below:
addEventListener:
The EventTarget.addEventListener() method adds the specified
EventListener-compatible object to the list of event listeners for the
specified event type on the EventTarget on which it's called. The
event target may be an Element in a document, the Document itself, a
Window, or any other object that supports events (such as
XMLHttpRequest).
onclick:
The onclick property returns the click event handler code on the
current element. When using the click event to trigger an action, also
consider adding this same action to the keydown event, to allow the
use of that same action by people who don't use a mouse or a touch
screen. Syntax element.onclick = functionRef; where functionRef is a
function - often a name of a function declared elsewhere or a function
expression. See "JavaScript Guide:Functions" for details.
There is also a syntax difference in use as you see in the below codes:
addEventListener:
// Function to change the content of t2
function modifyText() {
var t2 = document.getElementById("t2");
if (t2.firstChild.nodeValue == "three") {
t2.firstChild.nodeValue = "two";
} else {
t2.firstChild.nodeValue = "three";
}
}
// add event listener to table
var el = document.getElementById("outside");
el.addEventListener("click", modifyText, false);
onclick:
function initElement() {
var p = document.getElementById("foo");
// NOTE: showAlert(); or showAlert(param); will NOT work here.
// Must be a reference to a function name, not a function call.
p.onclick = showAlert;
};
function showAlert(event) {
alert("onclick Event detected!");
}
I guess Chris Baker pretty much summed it up in an excellent answer but I would like to add to that with addEventListener() you can also use options parameter which gives you more control over your events. For example - If you just want to run your event once then you can use { once: true } as an option parameter when adding your event to only call it once.
function greet() {
console.log("Hello");
}
document.querySelector("button").addEventListener('click', greet, { once: true })
The above function will only print "Hello" once.
Also, if you want to cleanup your events then there is also the option to removeEventListener(). Although there are advantages of using addEventListener() but you should still be careful if your targeting audience is using Internet Explorer then this method might not work in all situation. You can also read about addEventListener on MDN, they gave quite a good explanation on how to use them.
If you are not too worried about browser support, there is a way to rebind the 'this' reference in the function called by the event. It will normally point to the element that generated the event when the function is executed, which is not always what you want. The tricky part is to at the same time be able to remove the very same event listener, as shown in this example: http://jsfiddle.net/roenbaeck/vBYu3/
/*
Testing that the function returned from bind is rereferenceable,
such that it can be added and removed as an event listener.
*/
function MyImportantCalloutToYou(message, otherMessage) {
// the following is necessary as calling bind again does
// not return the same function, so instead we replace the
// original function with the one bound to this instance
this.swap = this.swap.bind(this);
this.element = document.createElement('div');
this.element.addEventListener('click', this.swap, false);
document.body.appendChild(this.element);
}
MyImportantCalloutToYou.prototype = {
element: null,
swap: function() {
// now this function can be properly removed
this.element.removeEventListener('click', this.swap, false);
}
}
The code above works well in Chrome, and there's probably some shim around making "bind" compatible with other browsers.
Using inline handlers is incompatible with Content Security Policy so the addEventListener approach is more secure from that point of view. Of course you can enable the inline handlers with unsafe-inline but, as the name suggests, it's not safe as it brings back the whole hordes of JavaScript exploits that CSP prevents.
It should also be possible to either extend the listener by prototyping it (if we have a reference to it and its not an anonymous function) -or make the onclick call a call to a function library (a function calling other functions).
Like:
elm.onclick = myFunctionList;
function myFunctionList(){
myFunc1();
myFunc2();
}
This means we never have to change the onclick call just alter the function myFunctionList() to do whatever we want, but this leaves us without control of bubbling/catching phases so should be avoided for newer browsers.
addEventListener lets you set multiple handlers, but isn't supported in IE8 or lower.
IE does have attachEvent, but it's not exactly the same.
The context referenced by 'this' keyword in JavasSript is different.
look at the following code:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
</head>
<body>
<input id="btnSubmit" type="button" value="Submit" />
<script>
function disable() {
this.disabled = true;
}
var btnSubmit = document.getElementById('btnSubmit');
btnSubmit.onclick = disable();
//btnSubmit.addEventListener('click', disable, false);
</script>
</body>
</html>
What it does is really simple. when you click the button, the button will be disabled automatically.
First when you try to hook up the events in this way button.onclick = function(),
onclick event will be triggered by clicking the button, however, the button will not be disabled because there's no explicit binding between button.onclick and onclick event handler. If you debug see the 'this' object, you can see it refers to 'window' object.
Secondly, if you comment btnSubmit.onclick = disable(); and uncomment
//btnSubmit.addEventListener('click', disable, false); you can see that the button is disabled because with this way there's explicit binding between button.onclick event and onclick event handler. If you debug into disable function, you can see 'this' refers to the button control rather than the window.
This is something I don't like about JavaScript which is inconsistency.
Btw, if you are using jQuery($('#btnSubmit').on('click', disable);), it uses explicit binding.
onclick is basically an addEventListener that specifically performs a function when the element is clicked. So, useful when you have a button that does simple operations, like a calculator button. addEventlistener can be used for a multitude of things like performing an operation when DOM or all content is loaded, akin to window.onload but with more control.
Note, You can actually use more than one event with inline, or at least by using onclick by seperating each function with a semi-colon, like this....
I wouldn't write a function with inline, as you could potentially have problems later and it would be messy imo. Just use it to call functions already done in your script file.
Which one you use I suppose would depend on what you want. addEventListener for complex operations and onclick for simple. I've seen some projects not attach a specific one to elements and would instead implement a more global eventlistener that would determine if a tap was on a button and perform certain tasks depending on what was pressed. Imo that could potentially lead to problems I'd think, and albeit small, probably, a resource waste if that eventlistener had to handle each and every click
in my Visual Studio Code, addEventListener has Real Intellisense on event
but onclick does not, only fake ones
let element = document.queryselector('id or classname');
element.addeventlistiner('click',()=>{
do work
})
<button onclick="click()">click</click>`
function click(){
do work
};

addEventListener vs onclick

What's the difference between addEventListener and onclick?
var h = document.getElementById("a");
h.onclick = dothing1;
h.addEventListener("click", dothing2);
The code above resides together in a separate .js file, and they both work perfectly.
Both are correct, but none of them are "best" per se, and there may be a reason the developer chose to use both approaches.
Event Listeners (addEventListener and IE's attachEvent)
Earlier versions of Internet Explorer implement JavaScript differently from pretty much every other browser. With versions less than 9, you use the attachEvent[doc] method, like this:
element.attachEvent('onclick', function() { /* do stuff here*/ });
In most other browsers (including IE 9 and above), you use addEventListener[doc], like this:
element.addEventListener('click', function() { /* do stuff here*/ }, false);
Using this approach (DOM Level 2 events), you can attach a theoretically unlimited number of events to any single element. The only practical limitation is client-side memory and other performance concerns, which are different for each browser.
The examples above represent using an anonymous function[doc]. You can also add an event listener using a function reference[doc] or a closure[doc]:
var myFunctionReference = function() { /* do stuff here*/ }
element.attachEvent('onclick', myFunctionReference);
element.addEventListener('click', myFunctionReference , false);
Another important feature of addEventListener is the final parameter, which controls how the listener reacts to bubbling events[doc]. I've been passing false in the examples, which is standard for probably 95% of use cases. There is no equivalent argument for attachEvent, or when using inline events.
Inline events (HTML onclick="" property and element.onclick)
In all browsers that support javascript, you can put an event listener inline, meaning right in the HTML code. You've probably seen this:
<a id="testing" href="#" onclick="alert('did stuff inline');">Click me</a>
Most experienced developers shun this method, but it does get the job done; it is simple and direct. You may not use closures or anonymous functions here (though the handler itself is an anonymous function of sorts), and your control of scope is limited.
The other method you mention:
element.onclick = function () { /*do stuff here */ };
... is the equivalent of inline javascript except that you have more control of the scope (since you're writing a script rather than HTML) and can use anonymous functions, function references, and/or closures.
The significant drawback with inline events is that unlike event listeners described above, you may only have one inline event assigned. Inline events are stored as an attribute/property of the element[doc], meaning that it can be overwritten.
Using the example <a> from the HTML above:
var element = document.getElementById('testing');
element.onclick = function () { alert('did stuff #1'); };
element.onclick = function () { alert('did stuff #2'); };
... when you clicked the element, you'd only see "Did stuff #2" - you overwrote the first assigned of the onclick property with the second value, and you overwrote the original inline HTML onclick property too. Check it out here: http://jsfiddle.net/jpgah/.
Broadly speaking, do not use inline events. There may be specific use cases for it, but if you are not 100% sure you have that use case, then you do not and should not use inline events.
Modern Javascript (Angular and the like)
Since this answer was originally posted, javascript frameworks like Angular have become far more popular. You will see code like this in an Angular template:
<button (click)="doSomething()">Do Something</button>
This looks like an inline event, but it isn't. This type of template will be transpiled into more complex code which uses event listeners behind the scenes. Everything I've written about events here still applies, but you are removed from the nitty gritty by at least one layer. You should understand the nuts and bolts, but if your modern JS framework best practices involve writing this kind of code in a template, don't feel like you're using an inline event -- you aren't.
Which is Best?
The question is a matter of browser compatibility and necessity. Do you need to attach more than one event to an element? Will you in the future? Odds are, you will. attachEvent and addEventListener are necessary. If not, an inline event may seem like they'd do the trick, but you're much better served preparing for a future that, though it may seem unlikely, is predictable at least. There is a chance you'll have to move to JS-based event listeners, so you may as well just start there. Don't use inline events.
jQuery and other javascript frameworks encapsulate the different browser implementations of DOM level 2 events in generic models so you can write cross-browser compliant code without having to worry about IE's history as a rebel. Same code with jQuery, all cross-browser and ready to rock:
$(element).on('click', function () { /* do stuff */ });
Don't run out and get a framework just for this one thing, though. You can easily roll your own little utility to take care of the older browsers:
function addEvent(element, evnt, funct){
if (element.attachEvent)
return element.attachEvent('on'+evnt, funct);
else
return element.addEventListener(evnt, funct, false);
}
// example
addEvent(
document.getElementById('myElement'),
'click',
function () { alert('hi!'); }
);
Try it: http://jsfiddle.net/bmArj/
Taking all of that into consideration, unless the script you're looking at took the browser differences into account some other way (in code not shown in your question), the part using addEventListener would not work in IE versions less than 9.
Documentation and Related Reading
W3 HTML specification, element Event Handler Attributes
element.addEventListener on MDN
element.attachEvent on MSDN
Jquery.on
quirksmode blog "Introduction to Events"
CDN-hosted javascript libraries at Google
The difference you could see if you had another couple of functions:
var h = document.getElementById('a');
h.onclick = doThing_1;
h.onclick = doThing_2;
h.addEventListener('click', doThing_3);
h.addEventListener('click', doThing_4);
Functions 2, 3 and 4 work, but 1 does not. This is because addEventListener does not overwrite existing event handlers, whereas onclick overrides any existing onclick = fn event handlers.
The other significant difference, of course, is that onclick will always work, whereas addEventListener does not work in Internet Explorer before version 9. You can use the analogous attachEvent (which has slightly different syntax) in IE <9.
In this answer I will describe the three methods of defining DOM event handlers.
element.addEventListener()
Code example:
const element = document.querySelector('a');
element.addEventListener('click', event => event.preventDefault(), true);
Try clicking this link.
element.addEventListener() has multiple advantages:
Allows you to register unlimited events handlers and remove them with element.removeEventListener().
Has useCapture parameter, which indicates whether you'd like to handle event in its capturing or bubbling phase. See: Unable to understand useCapture attribute in addEventListener.
Cares about semantics. Basically, it makes registering event handlers more explicit. For a beginner, a function call makes it obvious that something happens, whereas assigning event to some property of DOM element is at least not intuitive.
Allows you to separate document structure (HTML) and logic (JavaScript). In tiny web applications it may not seem to matter, but it does matter with any bigger project. It's way much easier to maintain a project which separates structure and logic than a project which doesn't.
Eliminates confusion with correct event names. Due to using inline event listeners or assigning event listeners to .onevent properties of DOM elements, lots of inexperienced JavaScript programmers thinks that the event name is for example onclick or onload. on is not a part of event name. Correct event names are click and load, and that's how event names are passed to .addEventListener().
Works in almost all browser. If you still have to support IE <= 8, you can use a polyfill from MDN.
element.onevent = function() {} (e.g. onclick, onload)
Code example:
const element = document.querySelector('a');
element.onclick = event => event.preventDefault();
Try clicking this link.
This was a way to register event handlers in DOM 0. It's now discouraged, because it:
Allows you to register only one event handler. Also removing the assigned handler is not intuitive, because to remove event handler assigned using this method, you have to revert onevent property back to its initial state (i.e. null).
Doesn't respond to errors appropriately. For example, if you by mistake assign a string to window.onload, for example: window.onload = "test";, it won't throw any errors. Your code wouldn't work and it would be really hard to find out why. .addEventListener() however, would throw error (at least in Firefox): TypeError: Argument 2 of EventTarget.addEventListener is not an object.
Doesn't provide a way to choose if you want to handle event in its capturing or bubbling phase.
Inline event handlers (onevent HTML attribute)
Code example:
Try clicking this link.
Similarly to element.onevent, it's now discouraged. Besides the issues that element.onevent has, it:
Is a potential security issue, because it makes XSS much more harmful. Nowadays websites should send proper Content-Security-Policy HTTP header to block inline scripts and allow external scripts only from trusted domains. See How does Content Security Policy work?
Doesn't separate document structure and logic.
If you generate your page with a server-side script, and for example you generate a hundred links, each with the same inline event handler, your code would be much longer than if the event handler was defined only once. That means the client would have to download more content, and in result your website would be slower.
See also
EventTarget.addEventListener() documentation (MDN)
EventTarget.removeEventListener() documentation (MDN)
onclick vs addEventListener
dom-events tag wiki
While onclick works in all browsers, addEventListener does not work in older versions of Internet Explorer, which uses attachEvent instead.
The downside of onclick is that there can only be one event handler, while the other two will fire all registered callbacks.
Summary:
addEventListener can add multiple events, whereas with onclick this cannot be done.
onclick can be added as an HTML attribute, whereas an addEventListener can only be added within <script> elements.
addEventListener can take a third argument which can stop the event propagation.
Both can be used to handle events. However, addEventListener should be the preferred choice since it can do everything onclick does and more. Don't use inline onclick as HTML attributes as this mixes up the javascript and the HTML which is a bad practice. It makes the code less maintainable.
As far as I know, the DOM "load" event still does only work very limited. That means it'll only fire for the window object, images and <script> elements for instance. The same goes for the direct onload assignment. There is no technical difference between those two. Probably .onload = has a better cross-browser availabilty.
However, you cannot assign a load event to a <div> or <span> element or whatnot.
An element can have only one event handler attached per event type, but can have multiple event listeners.
So, how does it look in action?
Only the last event handler assigned gets run:
const button = document.querySelector(".btn")
button.onclick = () => {
console.log("Hello World");
};
button.onclick = () => {
console.log("How are you?");
};
button.click() // "How are you?"
All event listeners will be triggered:
const button = document.querySelector(".btn")
button.addEventListener("click", event => {
console.log("Hello World");
})
button.addEventListener("click", event => {
console.log("How are you?");
})
button.click()
// "Hello World"
// "How are you?"
IE Note: attachEvent is no longer supported. Starting with IE 11, use addEventListener: docs.
One detail hasn't been noted yet: modern desktop browsers consider different button presses to be "clicks" for AddEventListener('click' and onclick by default.
On Chrome 42 and IE11, both onclick and AddEventListener click fire on left and middle click.
On Firefox 38, onclick fires only on left click, but AddEventListener click fires on left, middle and right clicks.
Also, middle-click behavior is very inconsistent across browsers when scroll cursors are involved:
On Firefox, middle-click events always fire.
On Chrome, they won't fire if the middleclick opens or closes a scroll cursor.
On IE, they fire when scroll cursor closes, but not when it opens.
It is also worth noting that "click" events for any keyboard-selectable HTML element such as input also fire on space or enter when the element is selected.
element.onclick = function() { /* do stuff */ }
element.addEventListener('click', function(){ /* do stuff */ },false);
They apparently do the same thing: listen for the click event and execute a callback function. Nevertheless, they’re not equivalent. If you ever need to choose between the two, this could help you to figure out which one is the best for you.
The main difference is that onclick is just a property, and like all object properties, if you write on more than once, it will be overwritten. With addEventListener() instead, we can simply bind an event handler to the element, and we can call it each time we need it without being worried of any overwritten properties.
Example is shown here,
Try it: https://jsfiddle.net/fjets5z4/5/
In first place I was tempted to keep using onclick, because it’s shorter and looks simpler… and in fact it is. But I don’t recommend using it anymore. It’s just like using inline JavaScript. Using something like – that’s inline JavaScript – is highly discouraged nowadays (inline CSS is discouraged too, but that’s another topic).
However, the addEventListener() function, despite it’s the standard, just doesn’t work in old browsers (Internet Explorer below version 9), and this is another big difference. If you need to support these ancient browsers, you should follow the onclick way. But you could also use jQuery (or one of its alternatives): it basically simplifies your work and reduces the differences between browsers, therefore can save you a lot of time.
var clickEvent = document.getElementByID("onclick-eg");
var EventListener = document.getElementByID("addEventListener-eg");
clickEvent.onclick = function(){
window.alert("1 is not called")
}
clickEvent.onclick = function(){
window.alert("1 is not called, 2 is called")
}
EventListener.addEventListener("click",function(){
window.alert("1 is called")
})
EventListener.addEventListener("click",function(){
window.alert("2 is also called")
})
Javascript tends to blend everything into objects and that can make it confusing. All into one is the JavaScript way.
Essentially onclick is a HTML attribute. Conversely addEventListener is a method on the DOM object representing a HTML element.
In JavaScript objects, a method is merely a property that has a function as a value and that works against the object it is attached to (using this for example).
In JavaScript as HTML element represented by DOM will have it's attributes mapped onto its properties.
This is where people get confused because JavaScript melds everything into a single container or namespace with no layer of indirection.
In a normal OO layout (which does at least merge the namespace of properties/methods) you would might have something like:
domElement.addEventListener // Object(Method)
domElement.attributes.onload // Object(Property(Object(Property(String))))
There are variations like it could use a getter/setter for onload or HashMap for attributes but ultimately that's how it would look. JavaScript eliminated that layer of indirection at the expect of knowing what's what among other things. It merged domElement and attributes together.
Barring compatibility you should as a best practice use addEventListener. As other answers talk about the differences in that regard rather than the fundamental programmatic differences I will forgo it. Essentially, in an ideal world you're really only meant to use on* from HTML but in an even more ideal world you shouldn't be doing anything like that from HTML.
Why is it dominant today? It's quicker to write, easier to learn and tends to just work.
The whole point of onload in HTML is to give access to the addEventListener method or functionality in the first place. By using it in JS you're going through HTML when you could be applying it directly.
Hypothetically you can make your own attributes:
$('[myclick]').each(function(i, v) {
v.addEventListener('click', function() {
eval(v.myclick); // eval($(v).attr('myclick'));
});
});
What JS does with is a bit different to that.
You can equate it to something like (for every element created):
element.addEventListener('click', function() {
switch(typeof element.onclick) {
case 'string':eval(element.onclick);break;
case 'function':element.onclick();break;
}
});
The actual implementation details will likely differ with a range of subtle variations making the two slightly different in some cases but that's the gist of it.
It's arguably a compatibility hack that you can pin a function to an on attribute since by default attributes are all strings.
You should also consider EventDelegation for that!
For that reason I prefer the addEventListener and foremost using it carefully and consciously!
FACTS:
EventListeners are heavy .... (memory allocation at the client side)
The Events propagate IN and then OUT again in relation to the DOM
tree. Also known as trickling-in and bubbling-out , give it a read
in case you don't know.
So imagine an easy example:
a simple button INSIDE a div INSIDE body ...
if you click on the button, an Event will ANYWAY
trickle in to BUTTON and then OUT again, like this:
window-document-div-button-div-document-window
In the browser background (lets say the software periphery of the JS engine) the browser can ONLY possibly react to a click, if it checks for each click done where it was targeted.
And to make sure that each possible event listener on the way is triggered, it kinda has to send the "click event signal" all the way from document level down into the element ... and back out again.
This behavior can then made use of by attaching EventListeners using e.g.:
document.getElementById("exampleID").addEventListener("click",(event) => {doThis}, true/false);
Just note for reference that the true/false as the last argument of the addEventListener method controls the behavior in terms of when is the event recognized - when trickling in or when bubbling out.
TRUE means, the event is recognized while trickling-in
FALSE means, the event is recognized on its way bubbling out
Implementing the following 2 helpful concepts also turns out much more intuitive using the above stated approach to handle:
You can also use event.stopPropagation() within the function
(example ref. "doThis") to prevents further propagation of the
current event in the capturing and bubbling phases. It does not,
however, prevent any default behaviors from occurring; for instance,
clicks on links are still processed.
If you want to stop those behaviors, you could use
event.preventDefault() within the function (example ref.
"doThis"). With that you could for example tell the Browser that if
the event does not get explicitly handled, its default action should
not be taken as it normally would be.
Also just note here for reference again: the last argument of the addEventListener method (true/false) also controls at which phase (trickling-in TRUE or bubbling out FALSE) the eventual effect of ".stopPropagation()" kicks in.
So ... in case you apply an EventListener with flag TRUE to an element, and combine that with the .stopPropagation() method, the event would not even get through to potential inner children of the element
To wrap it up:
If you use the onClick variant in HTML ... there are 2 downsides for me:
With addEventListener, you can attach multiple onClick-events to the same, respectively one single element, but thats not possible using onClick (at least thats what I strongly believe up to now, correct me if I am wrong).
Also the following aspect is truly remarkable here ... especially the code maintenance part (didn't elaborate on this so far):
In regards to event delegation, it really boils down to this. If some
other JavaScript code needs to respond to a click event, using
addEventListener ensures you both can respond to it. If you both try
using onclick, then one stomps on the other. You both can't respond if
you want an onclick on the same element. Furthermore, you want to keep your behavior as separate as you can from the HTML in case you need to change it later. It would suck to have 50 HTML files to update instead of one JavaScript file.
(credit to Greg Burghardt, addEventListener vs onclick with regards to event delegation )
This is also known by the term "Unobtrusive JavaScript" ... give it a read!
According to MDN, the difference is as below:
addEventListener:
The EventTarget.addEventListener() method adds the specified
EventListener-compatible object to the list of event listeners for the
specified event type on the EventTarget on which it's called. The
event target may be an Element in a document, the Document itself, a
Window, or any other object that supports events (such as
XMLHttpRequest).
onclick:
The onclick property returns the click event handler code on the
current element. When using the click event to trigger an action, also
consider adding this same action to the keydown event, to allow the
use of that same action by people who don't use a mouse or a touch
screen. Syntax element.onclick = functionRef; where functionRef is a
function - often a name of a function declared elsewhere or a function
expression. See "JavaScript Guide:Functions" for details.
There is also a syntax difference in use as you see in the below codes:
addEventListener:
// Function to change the content of t2
function modifyText() {
var t2 = document.getElementById("t2");
if (t2.firstChild.nodeValue == "three") {
t2.firstChild.nodeValue = "two";
} else {
t2.firstChild.nodeValue = "three";
}
}
// add event listener to table
var el = document.getElementById("outside");
el.addEventListener("click", modifyText, false);
onclick:
function initElement() {
var p = document.getElementById("foo");
// NOTE: showAlert(); or showAlert(param); will NOT work here.
// Must be a reference to a function name, not a function call.
p.onclick = showAlert;
};
function showAlert(event) {
alert("onclick Event detected!");
}
I guess Chris Baker pretty much summed it up in an excellent answer but I would like to add to that with addEventListener() you can also use options parameter which gives you more control over your events. For example - If you just want to run your event once then you can use { once: true } as an option parameter when adding your event to only call it once.
function greet() {
console.log("Hello");
}
document.querySelector("button").addEventListener('click', greet, { once: true })
The above function will only print "Hello" once.
Also, if you want to cleanup your events then there is also the option to removeEventListener(). Although there are advantages of using addEventListener() but you should still be careful if your targeting audience is using Internet Explorer then this method might not work in all situation. You can also read about addEventListener on MDN, they gave quite a good explanation on how to use them.
If you are not too worried about browser support, there is a way to rebind the 'this' reference in the function called by the event. It will normally point to the element that generated the event when the function is executed, which is not always what you want. The tricky part is to at the same time be able to remove the very same event listener, as shown in this example: http://jsfiddle.net/roenbaeck/vBYu3/
/*
Testing that the function returned from bind is rereferenceable,
such that it can be added and removed as an event listener.
*/
function MyImportantCalloutToYou(message, otherMessage) {
// the following is necessary as calling bind again does
// not return the same function, so instead we replace the
// original function with the one bound to this instance
this.swap = this.swap.bind(this);
this.element = document.createElement('div');
this.element.addEventListener('click', this.swap, false);
document.body.appendChild(this.element);
}
MyImportantCalloutToYou.prototype = {
element: null,
swap: function() {
// now this function can be properly removed
this.element.removeEventListener('click', this.swap, false);
}
}
The code above works well in Chrome, and there's probably some shim around making "bind" compatible with other browsers.
Using inline handlers is incompatible with Content Security Policy so the addEventListener approach is more secure from that point of view. Of course you can enable the inline handlers with unsafe-inline but, as the name suggests, it's not safe as it brings back the whole hordes of JavaScript exploits that CSP prevents.
It should also be possible to either extend the listener by prototyping it (if we have a reference to it and its not an anonymous function) -or make the onclick call a call to a function library (a function calling other functions).
Like:
elm.onclick = myFunctionList;
function myFunctionList(){
myFunc1();
myFunc2();
}
This means we never have to change the onclick call just alter the function myFunctionList() to do whatever we want, but this leaves us without control of bubbling/catching phases so should be avoided for newer browsers.
addEventListener lets you set multiple handlers, but isn't supported in IE8 or lower.
IE does have attachEvent, but it's not exactly the same.
The context referenced by 'this' keyword in JavasSript is different.
look at the following code:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
</head>
<body>
<input id="btnSubmit" type="button" value="Submit" />
<script>
function disable() {
this.disabled = true;
}
var btnSubmit = document.getElementById('btnSubmit');
btnSubmit.onclick = disable();
//btnSubmit.addEventListener('click', disable, false);
</script>
</body>
</html>
What it does is really simple. when you click the button, the button will be disabled automatically.
First when you try to hook up the events in this way button.onclick = function(),
onclick event will be triggered by clicking the button, however, the button will not be disabled because there's no explicit binding between button.onclick and onclick event handler. If you debug see the 'this' object, you can see it refers to 'window' object.
Secondly, if you comment btnSubmit.onclick = disable(); and uncomment
//btnSubmit.addEventListener('click', disable, false); you can see that the button is disabled because with this way there's explicit binding between button.onclick event and onclick event handler. If you debug into disable function, you can see 'this' refers to the button control rather than the window.
This is something I don't like about JavaScript which is inconsistency.
Btw, if you are using jQuery($('#btnSubmit').on('click', disable);), it uses explicit binding.
onclick is basically an addEventListener that specifically performs a function when the element is clicked. So, useful when you have a button that does simple operations, like a calculator button. addEventlistener can be used for a multitude of things like performing an operation when DOM or all content is loaded, akin to window.onload but with more control.
Note, You can actually use more than one event with inline, or at least by using onclick by seperating each function with a semi-colon, like this....
I wouldn't write a function with inline, as you could potentially have problems later and it would be messy imo. Just use it to call functions already done in your script file.
Which one you use I suppose would depend on what you want. addEventListener for complex operations and onclick for simple. I've seen some projects not attach a specific one to elements and would instead implement a more global eventlistener that would determine if a tap was on a button and perform certain tasks depending on what was pressed. Imo that could potentially lead to problems I'd think, and albeit small, probably, a resource waste if that eventlistener had to handle each and every click
in my Visual Studio Code, addEventListener has Real Intellisense on event
but onclick does not, only fake ones
let element = document.queryselector('id or classname');
element.addeventlistiner('click',()=>{
do work
})
<button onclick="click()">click</click>`
function click(){
do work
};

Properly bind Javascript events

I am looking for the most proper and efficient way to bind Javascript events; particularly the onload event (I would like the event to occur after both the page AND all elements such as images are loaded). I know there are simple ways to do this in jQuery but I would like the more efficient raw Javascript method.
There are two different ways to do it. Only one will work; which one depends on the browser. Here's a utility method that uses both:
function bindEvent(element, type, handler) {
if(element.addEventListener) {
element.addEventListener(type, handler, false);
} else {
element.attachEvent('on'+type, handler);
}
}
In your case:
bindEvent(window, 'load', function() {
// all elements such as images are loaded here
});
I know you did only ask about how to bind events. But Ooooo boy the fun doesn't end there. There's a lot more to getting this right cross-browser than just the initial binding.
#d.'s answer will suffice just fine for the specific case of the load event of window you're looking for. But it may give novice readers of your code a false sense of "getting it right". Just because you bound the event doesn't mean you took care to normalize it. You may be better of just fixing window.onload:
window.onload = (function(onload) {
return function(event) {
onload && onload(event);
// now do your thing here
}
}(window.onload))
But for the general case of event binding #d.'s answer is so far from satisfying as to be frustrating. About the only thing it does right is use feature-detection as opposed to browser detection.
Not to go on too much of a rant here but JavaScript event binding is probably the #1 reason to go with a JavaScript library. I don't care which one it is, other people have fixed this problem over and over and over again. Here're the issues in a home-brewed implementation once inside your handler function:
How do I get a hold of the event object itself?
How do I prevent the default action of the event (eg clicking on a link but not navigating)
Why does this point to the window object all the time?
(Re mouse events) What are the x/y coords of the event?
Which mouse button triggered the event?
Was it a Ctrl-click or just a regular click?
What element was the event actually triggered on?
What element is the event going to? (ie relatedTarget, say for blur)
How do I cancel the bubbling of the event up through its parent DOM?
(Re event bubbling) what element is actually receiving the event now? (ie currentTarget)
Why can't I get the freaking char code from this keydown event?
Why is my page leaking memory when I add all these event handlers?? Argh!
Why can't I Unbind this anonymous function I bound earlier?
And the list goes on...
The only good reason to roll your own in these days is for learning. And that's fine. Still, read PPK's Intro to browser events. Look at the jQuery source. Look at the Prototype source. You won't regret it.
Something like that
window.onload = (function(onload) {
return function(event) {
onload && onload(event);
$(".loading-overlay .spinner").fadeOut(300),
$(".loading-overlay").fadeOut(300);
$("body").css({
overflow: "auto",
height: "auto",
position: "relative"
})
}
}(window.onload));
window.onload = function() {
// ...
};

Categories