Correct Usage of Addeventlistener()/Attachevent()

What is the difference between addEventListener and attachEvent?

Quick answer: you have to use attachEvent if your browser returns undefined == window.addEventListener. Thing is the former is a non-standard JS function implemented in IE8 and previous versions, while addEventListener is supported by IE9+ (and all the other browsers).

So the big question is: are you gonna support IE8-?

Margin note: window.onload = whatever will override any attached event listeners. This is why addEventListener is used: to add a function to the event's stack, instead of overwriting it.

JavaScript attach events to elements rendered dynamically

You have to reload all.js after each new element. That is the only solution I can think of.

After action that creates an element you'll call a function:

// removed, see Edit

this shall reevalute all.js and listeners from all.js shall attach to elements being in DOM.

This is very inefficient solution, so if you make several dynamic updates, reload all.js at the end of all updates, not after every single update.

This also mean, that some statefull variables from all.js might be reinitialized, counters may be reset to zero, etc.

I would personally never do this kind of piggy patching, but if you have no other choice, give it a try.

Edit

Tested working code

function reloadAllJs(){
var path = "all.js"
, oldScript = document.querySelector("script[src^='" + path + "']")
, newScript = document.createElement("script")
;
// adding random get parameter to prevent caching
newScript.src = path + "?timestamp=" + Date.now();
oldScript.parentNode.replaceChild(newScript, oldScript);
}

querySelector and Date.now()are IE9+ compatible, for support IE8- the code must be modified.

Update

IE8- compatible version (tested in IE7)

function reloadAllJs(){
var path = "all.js"
, scripts = document.getElementsByTagName("script")
, oldScript
, newScript = document.createElement("script")
;

for(var i = 0, s; s = scripts[i]; i++) {
if (s.src.indexOf(path) !== -1) {
oldScript = s;
break;
}
}

// adding random get parameter to prevent caching
newScript.src = path + "?timestamp=" + (new Date()).getTime();
oldScript.parentNode.replaceChild(newScript, oldScript);
}

Note: IE8 does not support addEventListener (it has very similar method attachEvent ), so if your all.js relies on addEventListener, then all.js is only IE9+ compatible.

Alternate shortcut for addEventListener()

Consider what happens if you try the following (I'm attaching the events to window because that is where you should listen for this event)

window.onload = function (e) {console.log('A');};
window.onload = function (e) {console.log('B');};

vs

window.addEventListener('load', function (e) {console.log('C');}, false);
window.addEventListener('load', function (e) {console.log('D');}, false);

From the first code block you will only see "B", but from the second you'll see both "C" and "D". Fiddle (please open console to see).

JavaScript add events cross-browser function implementation: use attachEvent/addEventListener vs inline events

With the 2nd solution, you have to manually call the previous functions, making it hard to remove specific listeners (which, to me, sounds like something you'd rather want than clearing all listeners), while on the first solution, you can only clear them all at the same time, unless you want to emulate the first functionality.

Personally, I always use the first solution, because it has the advantage of not having to worry about clearing possible other event listeners.

The mozilla wiki also lists the advantages that the first solution works on any DOM element, not just HTML elements, and that it allows finer grained control over the phase when the listener gets activated (capturing vs. bubbling) with the third argument.

How to add a custom right-click menu to a webpage?

Answering your question - use contextmenu event, like below:

if (document.addEventListener) {  document.addEventListener('contextmenu', function(e) {    alert("You've tried to open context menu"); //here you draw your own menu    e.preventDefault();  }, false);} else {  document.attachEvent('oncontextmenu', function() {    alert("You've tried to open context menu");    window.event.returnValue = false;  });}
<body>  Lorem ipsum...</body>

addEventListener vs onclick

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

Click event doesn't work on dynamically generated elements

The click() binding you're using is called a "direct" binding which will only attach the handler to elements that already exist. It won't get bound to elements created in the future. To do that, you'll have to create a "delegated" binding by using on().

Delegated events have the advantage that they can process events from descendant elements that are added to the document at a later time.

Source

Here's what you're looking for:

var counter = 0;
$("button").click(function() { $("h2").append("<p class='test'>click me " + (++counter) + "</p>")});
// With on():
$("h2").on("click", "p.test", function(){ alert($(this).text());});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script><h2></h2><button>generate new element</button>


Related Topics



Leave a reply



Submit