This is the project page for my entry into the addEvent() recoding contest. It works in all of the modern browsers: Windows IE 5+, Mozilla, Opera, and Safari. The code meets every item outlined in the guideline – attempting to be as short and simple as possible. You can view a demo of it in action.
This library consists of two functions: addEvent and removeEvent. To use them, simply copy the code from below, paste it into your Javascript code, and call it using these methods:
addEvent( object, eventType, function );
The ‘object’ parameter should be the object upon which you want the event to be called.
The ‘eventType’ parameter should hold the name of the event, for example: ‘click’, ‘mouseover’, ‘load’, ‘submit’, etc. More can be found here.
The ‘function’ parameter should be a reference to a function that you wish to have called whenever the event fires. One parameter will be passed to ‘function’ – the event object.
Some examples of addEvent in use:
addEvent( document.getElementById('foo'), 'click', doSomething ); addEvent( obj, 'mouseover', function(){ alert('hello!'); } );
removeEvent( object, eventType, function );
removeEvent is virtually identical to addEvent, with the obvious difference: Instead of the function being added to the event handler, it is removed instead. All of the above code and parameters applies to this function.
The code, itself, is very short and simple – only 15 lines long:
function addEvent( obj, type, fn ) { if ( obj.attachEvent ) { obj['e'+type+fn] = fn; obj[type+fn] = function(){obj['e'+type+fn]( window.event );} obj.attachEvent( 'on'+type, obj[type+fn] ); } else obj.addEventListener( type, fn, false ); } function removeEvent( obj, type, fn ) { if ( obj.detachEvent ) { obj.detachEvent( 'on'+type, obj[type+fn] ); obj[type+fn] = null; } else obj.removeEventListener( type, fn, false ); }
Much of the above code is trying to fix a serious problem with Internet Explorer. The code has to be this troublesome due to the fact that when your attached function gets fired, the ‘this’ reference refers to the worthless ‘window’, when, in fact, it should refer to the parent object. An explanation of the key points:
obj['e'+type+fn] = fn;
This makes the function a child of the specified object. The key, which is placed in the object hash, is (hopefully) unique and won’t collide with any other function additions.
obj[type+fn] = function(){ obj['e'+type+fn]( window.event ); }
This line creates an anonymous function who, once executed, will fire the previously attached function – passing it the global event object. This whole function is being attached to the object so that it can be removed later, using the removeEvent() function.
Finally, for more information on the attachEvent, detachEvent, addEventListener, and removeEventListener functions – please refer to the excellent resource at Quirksmode.
If you have any additional questions concerning the above code, please feel free to ask.
Mark Wubben (September 9, 2005 at 5:21 am)
You need to reset the `obj` variable in `addEvent()` to prevent memory leakage. Other than that, nice work!
John Resig (September 9, 2005 at 8:23 am)
Mark Ah! Thanks for catching that. For now, I’m going to set the value equal to null – I would’ve used the ‘delete’ function but one of the requirements for this contest is to support IE 5 (which doesn’t have ‘delete’). I’ll keep checking and see if there’s a better way to do this. Thanks again!
Martin (September 10, 2005 at 5:10 am)
How about setting it to undefined by assigning void 0?
QuirksBlog (October 18, 2005 at 10:38 am)
… and the winner is …
Well, that wasn’t what anyone would call fast. Scott, Dean and I all had trouble making time to judge the contest. Besides, the quality of most of the entries was less and their length far greater than we’d expected. We had to wade through dozens of …
Dustin Diaz (October 18, 2005 at 4:58 pm)
Congratulations. You won. Prepare for your code to be stolen by everyone ;)
*that’s a good thing ;) *
QuirksBlog (October 19, 2005 at 5:49 am)
… and the winner is …
Well, that wasn’t what anyone would call fast. Scott, Dean and I all had trouble making time to judge the contest. Besides, the quality of most of the entries was less and their length far greater than we’d expected. We had to wade through dozens of …
Michael Niggel (October 19, 2005 at 8:11 am)
Congratulations.
Nice to see it come out of RIT, too.
(2003, Graphic Design)
MH (October 19, 2005 at 10:42 am)
Maybe this is due to some extremely rare combination of settings that only affects me, but man, this site is nigh-impossible to read!
No, it’s not me, checked the stylesheet:
background: #212121;
…
color: #333;
How ’bout some contrast?
MH (October 19, 2005 at 10:55 am)
Hm–now it’s working. The white block appeared. For some reason, this and other pages don’t finish loading for a loooong time (like, several minutes).
Jim Van Fleet (October 19, 2005 at 3:41 pm)
You are not alone, MH! (Firefox 1.07, WinXP)
John Resig (October 19, 2005 at 8:32 pm)
Yeah, I’m definitely encountering some very strange WordPress bug right now – I’m trying to figure out what’s up.
John Resig (October 19, 2005 at 8:37 pm)
Yeah, I’m definitely encountering some very strange WordPress bug right now – I’m trying to figure out what’s up.
Matt Todd (October 20, 2005 at 12:03 am)
The same problem occurs in Safari v1.3.1 as well.
Is there part of the code that changes the background color when the page is finally loaded? Is it an image? There has to be some reason why it would be delayed in running or downloading. If it were part of the CSS, it should not matter if it didn’t load because the whole page should look like crap…
M.T.
Erez (November 5, 2005 at 1:31 pm)
Great code! Can you explain me why and where should the ‘obj’ be reset?
E.E.
Rico (November 6, 2005 at 11:52 pm)
Wonderful. :)
Can we use this little snippet for our own projects? Pretty please?
Pauly (November 16, 2005 at 11:22 am)
Anyone know how I can make a reference to a function with a parameter? I can’t even figure out how to search for this… passing a reference to a function with a parameter to a function as a parameter… doing my swede in. Nice work btw.
Pauly (November 16, 2005 at 11:26 am)
Ignore that actually, I’ve gone mad, cheers!
Pauly (November 18, 2005 at 11:02 am)
Don’t know if anyone’s going to read this, but I can’t figure out the syntax to do something like
addEvent( buttonObject, “click”, function () { doSomethingElseWith( formObject ) } );
doSomethingElseWith() is being called, but formObject is not being passed, I am obviously missing something dumb… Source code is at http://www.clarkeology.com/js/ajaxer.js
Ashley Bowers (November 23, 2005 at 7:21 pm)
Cool demo, can we all use this for our own someday?
Geoffrey Swenson (December 8, 2005 at 5:23 pm)
I am having some trouble wrapping my head around this. I have an SVG object writer that with some listener events. I have to expressly refer to my sandbox object in the scripts (mObjSandBox).
And yes, this is running in IE, so the events have no actual “this” object.
This code works, but would get rather horrible if I had more than one sandbox on the page. Besides, I am trying to get the sandbox class to do all of the work so that this is easy to clone on other pages.
function Down(evt)
{
mObjSandBox.lastX = evt.clientX
mObjSandBox.lastY = evt.clientY
mObjSandBox.down = true
}
function Up(evt)
{
mObjSandBox.down = false
}
function Move(evt)
{
if( ! mObjSandBox.down )
{
return;
}
var x = evt.clientX;
var y = evt.clientY;
var dx = x – mObjSandBox.lastX;
var dy = y – mObjSandBox.lastY;
mObjSandBox.lastX = x;
mObjSandBox.lastY = y;
if( evt.shiftKey )
{
mObjSandBox.svgDoc.documentElement.currentTranslate.x += dx;
mObjSandBox.svgDoc.documentElement.currentTranslate.y += dy;
}
else
{
mObjSandBox.tx += dx;
mObjSandBox.ty += dy;
mObjSandBox.svgDoc.rootElement.setAttribute(“transform”, “translate(“+mObjSandBox.tx+”,”+mObjSandBox.ty+”)” )
}
}
lva (January 4, 2006 at 5:44 am)
Hello. I was just reading this, and it made me wonder if you couldn’t improve things by defining the function like this instead:
if ( document.attachEvent ) {
function addEvent( obj, evType, fn ) {
...
}
} else if ( document.addEventListener ) {
function addEvent( obj, evType, fn ) {
...
}
}
… ie. check for attachEvent only when you define the function, rather than every time you call it.
Please excuse me (and correct me) if I’m wrong!
Luke Matuszewski (February 10, 2006 at 9:59 am)
Win IE 5 has delete operator (IE 4 had it too) (delete is present since JScript 3.0). Tested on standalone versions from: downloads.skyzyx.com/
Britney (April 2, 2006 at 2:43 pm)
Thanks Luke for the link and Pauly i had the same problem but just restarted my puter and it fixed it !
Shuriken (April 21, 2006 at 3:11 pm)
Shuriken
I am Petra, very interesting article that contained the information I was searching for in Google, thanks.
Bundle (June 10, 2006 at 1:45 am)
Anyone able to make this work on IE for Mac? I love the simplicity of this but I’m sad I can’t view it in all my browers. BTW, I’m not a programmer so I’m not clever enough to deal with this on my own. Fanks.
Jonass (July 3, 2006 at 9:31 am)
try to change false to true for safari support
obj.addEventListener( type, fn, true);
Matt (July 8, 2006 at 7:01 am)
Well, nice job: Simple, shot, and works well. I use it on my website, so many thanks :-)
Douglas (July 14, 2006 at 1:28 pm)
Intersting approach to fixing an annoying problem. A few observations….
First, it does not appear as though the pointer set up by the following line in addEvent is ever cleaned up:
obj[‘e’+type+fn] = fn;
As far as I can tell, the DOM “obj” will always keep a reference to the given function even after the event has been removed via “removeEvent”. Adding the following line in “removeEvent” should alleviate the issue:
obj[‘e’+type+fn] = null;
Second, I believe that functions attached to a DOM node via attachEvent automatically receive the event object as the first argument, so, the line:
obj[type+fn] = function(){ obj[‘e’+type+fn]( window.event ); }
can be changed to:
obj[type+fn] = function(evt){ obj[‘e’+type+fn](evt); }
the original code assumes the “obj” DOM node has the same window context as the “addEvent” function (which is not always the case).
Third, and most important, as Mark Wubben pointed out in the first comment, reference to the “obj” variable in addEvent causes a memory leak. The next few comments suggest ways to correct the issue, but, has anyone tried their own suggestions? None of them work as far as I can tell. Setting “obj=null” or “obj=void 0” throws an exception when the event is triggered (since the reference to “obj” is now different) and using “delete obj” doesn’t actually clean up the “obj” variable in this instance, leaving IE users with a memory leak.
I really hope I’m overlooking something obvious, especially with my third point, otherwise, anyone using this script will create two new memory leaks (for IE users) in their code every time addEvent is called, one of which will persist, even after visitors navigate away from the page.
Dao (July 26, 2006 at 12:47 pm)
Well, there’s much I don’t like about event handling and your addEvent only helps little. But that’s how the contest was set, so it’s not your fault. However, feel free to take a look at my solution :)
http://en.design-noir.de/webdev/JS/addEvent/
Javier (August 7, 2006 at 3:02 am)
What about this instead :
function attachEvent(obj, eventType, handler){
if(obj.attachEvent)
obj.attachEvent(‘on’ + eventType, function(){handler.call(obj)});
else
obj.addEventListener(eventType, handler, false);
}
Douglas (August 14, 2006 at 7:35 am)
Javier,
If only it were so easy, unfortunately, the problem with your example is that users will not be able to remove their previously added “handler” functions from the “obj” since you are wrapping it within an anonymous function.
toni (September 1, 2006 at 11:26 pm)
To access “this” on IE, we can use window.event.srcElement. haven’t try it yet but that’s what I found in http://msdn.microsoft.com/workshop/author/dhtml/reference/events/onclick.asp
Dao (September 10, 2006 at 1:26 pm)
toni, event.srcElement [IE] is tantamount to event.target [W3C]. “this” is tantamount to event.currentTarget [W3C].
mynthon (September 22, 2006 at 1:55 pm)
Hi! ive found this functions very useful. Im no js guru, but i try :P
Ive changed your functions, so now i can pass params to event handler. Please check if its good or only crap:
function addEvent( obj, type, fn, p ){
obj[“e”+type+fn] = fn;
if (obj.addEventListener){
eval( ‘obj.addEventListener( type, function(event){obj[“e”+type+fn](event, ‘ + p + ‘)}, false );’ );
} else if (obj.attachEvent){
obj[type+fn] = function() { eval ( ‘obj[“e”+type+fn](window.event, ‘ + p + ‘);’ ); }
obj.attachEvent(“on”+type, obj[type+fn]);
}
}
addEvent(obj, ‘click’, al, “‘param1’, ‘param2′”);
function al(e, a, b){
alert (a + “:” + b);
//prevent default action if link clicked
(e.preventDefault) ? e.preventDefault() : (e.returnValue = false);
}
best regards
Antony (October 4, 2006 at 2:20 pm)
Third, and most important, as Mark Wubben pointed out in the first comment, reference to the “obj†variable in addEvent causes a memory leak. The next few comments suggest ways to correct the issue, but, has anyone tried their own suggestions? None of them work as far as I can tell. Setting “obj=null†or “obj=void 0″ throws an exception when the event is triggered (since the reference to “obj†is now different) and using “delete obj†doesn’t actually clean up the “obj†variable in this instance, leaving IE users with a memory leak.
I really hope I’m overlooking something obvious, especially with my third point, otherwise, anyone using this script will create two new memory leaks (for IE users) in their code every time addEvent is called, one of which will persist, even after visitors navigate away from the page.
davidflanagan.com (October 25, 2006 at 12:47 am)
IE, event objects, and attachEvent()
In the 5th edition of my JavaScript book, I wrote: Although the IE event model provides event details in an Event object, it never passes Event objects as arguments to event handlers. I don’t know how I know this:…
Yogesh (December 12, 2006 at 8:58 am)
How to remove event if condition is there. Look at following example
onblur=’if (ValidateAndConvertDate(this)) SingleActionChanged(this, “SDTF”); else RestoreSingleComparison(this, “SDTF”);’
Stefan Van Reeth (January 18, 2007 at 1:38 pm)
I’ve written this one ages ago, and addressed all issues fairly easy. In my version, addEvent and removeEvent belong to a class and I use an extra clas to store the set events and adapted handlers in. For you guys, I’ve backported my functionality to this example. Instead of an extra class, we will use an extra hash to store the adapted handlers.
Wait, it will get clear in a minute :). First the code:
var funcs = new Object();
function addEvent( obj, type, fn ) {
if ( obj.attachEvent ) {
if ( typeof funcs[type+fn] != “function” ) {
funcs[type+fn] = function() {
fn.apply(window.event.srcElement);
};
obj.attachEvent( ‘on’+type, funcs[type+fn] );
}
obj = null;
} else {
obj.addEventListener( type, fn, false );
}
}
function removeEvent( obj, type, fn ) {
if ( obj.detachEvent ) {
obj.detachEvent( ‘on’+type, funcs[type+fn] );
funcs[type+fn] = null;
obj = null;
} else {
obj.removeEventListener( type, fn, false );
}
}
So, what we have here is a simplified version of what I use, but it’s easier to explain like this. And after all, not all you guys like to have elaborate objects when they only want those two functions.
At least the two major flaws in IE are adressed: the ‘this’ issue and the memory leakage.
Now, contrary to what Dao states, using the funcs like I made ’em does give us a reference to the element the event originated from. So from now on, ‘this’ will point to that element instead to the window object in event handlers.
Now the memory leakage. It does seem to work but, to be honest, IE makes it quite difficult to measure that. Memory usage in IE goes up all the time, even without leakages in the script. Even opening the context menu could trigger this so… Let’s just say the amount of memory now leaking is due to other flaws in IE, but those can’t be addressed by us, no?
Why I like this version better than the one above? Well, all adapted functions (the event handlers) are stored in one central place. No more polluting the DOM. And I only need to use one adapted function.
For those who think I post this without testing my code: give me a mail and I’ll send you a two files which make up a simple test. I even stayed in line with the code formatting above. Not my style, but that’s just taste off course :). I can be contacted at: stefan dot van dot reeth at gmail dot com.
Stefan Van Reeth (January 18, 2007 at 2:35 pm)
@ mynthon
If it works like expected, without any gotcha’s, it’s no crap. Maybe not the most elegant way to do it. But that’s something else altogether…
Now I’ve not met many situations where passing parameters to handlers is necessary. Because in essence, a handler is a reaction on a change of condition. So when that change demands for other things to happen, I let the handler look up all needed values and pas them off to another func.
Way easier and less clutter. Surely, one can entangle code to do it in one go, but to me it seems more like you have to rethink your design when you often end up in that situation.
In your example above: why don’t you just make another function that returns the needed values for the alert? Then you just have to call it from the handler and hey presto, you got a & b. This way you can use a version of addEvent like John’s or mine.
Maybe a general guideline is in place here. Try to make your functions atomic. That means: let them do just what they need to do. So addEvent to add an event, removeEvent to remove one and getAlertValuesForOnclickHandler to… Yeah, you got it. Don’t try to make functions that do it all, and then also do dishwashing, let the dog out, fill in tax forms and so on. — Man, would I be happy when I can code that :D —
Hope that helps.
Lucas (January 23, 2007 at 10:37 pm)
Stefan, I think there is a situation where a parameter could be used.
I’m making a Greasemonkey script that build a list of names and IDs, and I want to click on the link and call function(ID)…
Greasemonkey won’t work if you build the link on a string… due to some restrictions you have to use addEventListener…
If it was a Select object it was ok to find out the selected value, but with simple links is there any simpler option than Payly’s?
Douglas (January 25, 2007 at 12:39 pm)
Stefan,
Congratulations on avoiding a memory leak in your code, unfortunately, your method of avoiding a memory leak relies on the faulty assumption that event.srcElement will refer to the DOM element that has the event listener.
As Dao alluded to in a previous comment, event.srcElement is equivalent to the W3C’s event.target NOT event.currentTarget which is what you would really want to use, but cannot, since IE doesn’t support event.currentTarget.
How is this a problem? In cases where an event listener is triggered by event bubbling, your addEvent function listener will be called in the wrong context (i.e. “this” refers to the wrong DOM element). Here is an example that demonstrates the problem (please include your addEvent function on the page when testing it)…
— Example begin ——
Click MeClick Me
var div=document.getElementById(“outerButton”);
addEvent(div, “click”, clicked);
function clicked () { alert(this.id); }
— Example end ——
Do you see the problem? When clicking on the span with id=”innerText”, you would expect that the “clicked” function would be called with “this” equal to the div element, but what is actually happening is the “clicked” function is called with “this” equal to the span element. When you click outside of the span, but inside the div, the “clicked” function is called correctly however. The above example is a common, real world, use case. The problem is even more apparent when attempting to use your technique with onmouseover/out/move events.
In short, you cannot use event.srcElement to reliably point to the DOM node that contains the event listener. Without event.srcElement, unfortunately, your example will have to rely on a memory leak in order to work.
Douglas (January 25, 2007 at 1:09 pm)
Stefan,
My example above is messed up due to the HTML tags being stripped out. You can view a web page containg the above example, demonstrating the problem of relying on event.srcElement, by going here: http://home.earthlink.net/~dcopi/stefan.html
My apologies if this message shows up twice, the last post I submitted did not show up and there was no indication whether posts containing URLs are delayed.
vinay (January 29, 2007 at 10:51 am)
can i use removeEvent somehow to remove the unload event itself??
Stefan Van Reeth (February 2, 2007 at 8:57 am)
Sorry for the late responses, but time is short :)
@Lucas
Well, the solution is what I proposed to mynthon: call a function from the event handler that aggregates the parameters you want to pass, and call the function that needs those next. Like this:
var div = document.getElementById(â€outerButtonâ€);
addEvent(div, “clickâ€, clicked);
function clicked() { theFunctionIWantedToCallFromTheEvent(this.ID); }
Way nicer to the eyes than constructing eval statements. So instead of adding code to add functionality that’s got nothing to do with the core business of an object, you delegate it to another object or a helper function. That way it’s easier to see how things work too. Because you keep the logic that belongs together grouped into components, instead of spreading it all over the codebase.
@Douglas
Very true. Guess I just never ever constructed something like that ;). No really, what I use is an object that handles all event things like addEvent, but also event bubbling is addressed. And in this case I would simply register a special onclick function part of my object collection, bubbling will be prevented by it and some synthetic event would secretely pass the onclick off to the outerdiv. In essence I circumvent the event handling of the browser and devised my own. Problem solved ;). When it has javascript, I get always “outerdiv” lol.
But that’s not an answer concerning THIS particular addEvent. True. This addEvent has this problem, and frankly I don’t care. It’s only an example I took out of what I use. In my codebase, it does not stand on it’s own. I feel your answer is a bit in the same league as Justin’s: it’s the same issue I addressed to Mynthon and Lucas in my opinion.
When I construct things, it’s done by adhering strictly to keeping functionality atomic . In that way, I end up with a class that has only the functionality concerning the core business. So my EventManager has addEvent, but also disallowBubbling and stuff. But while EventManager has tons of stuff concerning events, it still is fairly light in footprint because all methods just concern themselves with only what they need to do. Most are even calls to methods of other event classes. In my opinion, I have the best of both worlds: compact code and all the functionality I need.
So I don’t fight that my addEvent indead has this flaw, but therefore it’s only an example. In the real world I use something altogether different which has the issue solved (and no, still no DOM polluting ;)). Because I also have my EventsBehaviour, EventsInformation, EventsCollection, and then some :). Now you know why I don’t have time to react faster: must…code…much lol.
But I greatly appreciate you took the time to construct the example page. Such things are really time eaters. So thank’s man.
Sadly it was not needed, but hey, how could you know? After all, I can’t start each reply with announcing I have a whole set of classes on the subject and I’m what will follow is only an example and yada yada yada. Still appreciate reactions though :). Even I can’t think of everything lol.
Cheers!
Stefan Van Reeth (February 2, 2007 at 11:33 am)
Oops, typo left: “…on the subject and what will follow is only an example and yada yada yada” was what was intended.
Alfred (February 23, 2007 at 7:23 pm)
THANK GOD!!!
I am glad you were imaginative enough to write this code because I just could not get around the problem. I ruthlessly plagurized the addEvent function. Now everything works great!
L@u (March 6, 2007 at 6:31 am)
Hi,
I have try to used the function addEvent (at point 41), but in IE I get an error
Error: ‘funcs’ is not defined.
Code: 0
pointing to the line: if ( typeof funcs[type+fn] != “function†) {
Anyone has an idea to fix this ?
Cheers,
L@u
Anthony Ettinger (March 7, 2007 at 3:26 pm)
For what it’s worth (i know the contest is over)…
but is there any foreseen problem with this addEvent()?
function addEvent(el, type, fn, capture) {
if (el.addEventListener) el.addEventListener(type, fn, capture);
else if (el.attachEvent) el.’on’+type = fn; //access ‘this’ IE6
else el[‘on’+type] = fn;
}
Diego Perini (March 16, 2007 at 2:05 pm)
There are so many missing things in the event
helpers I have seen so far and that’s because
of my slightly different working environment.
I obviously have my own scripts to do this but
I really have just collected around and have
to say “thanks” to many people like you if
I could come to a solution for my needs.
I would like to stress a bit on the list of
things I believe important in primitives like
these addEvent/removeEvent.
Our good addEvent/RemoveEvent helpers should
have a minimal of these features/options:
1) fix the “this” keyword (everybody does this)
2) fix the “event” source (not always the current window)
3) provide missing w3c “target” and other properties (some do this)
4) provide missing w3c “preventDefault” and “stopPropagation” methods
5) event must be removed (most helpers seems to do it but do not…)
6) options to fix or change the order of the events (most don’t do)
7) options to use w3c or inline registration (most don’t do)
8) returnValue must be preserved correctly (very few helpers do)
I would like to hear if I am missing/overlooking something, and if you believe that all these changes may badly affect current implementations.
Cheers,
Diego
Eric Gerds (March 26, 2007 at 9:12 pm)
There is a bug in IE when obj = window. The ‘this’ keyword will not always work as expected.
Example,
addEvent(window, “load”, function(){alert( this==window && window==this )})
Joseph Riofrio (May 27, 2007 at 3:56 pm)
hi, do you know what happened with the contest?
codepoet (June 28, 2007 at 3:15 pm)
1) fix the “this†keyword (everybody does this)
2) fix the “event†source (not always the current window)
3) provide missing w3c “target†and other properties (some do this)
4) provide missing w3c “preventDefault†and “stopPropagation†methods
5) event must be removed (most helpers seems to do it but do not…)
6) options to fix or change the order of the events (most don’t do)
7) options to use w3c or inline registration (most don’t do)
8) returnValue must be preserved correctly (very few helpers do)
What about parameter related items like:
9) Parameter evaluation time: (design:runtime:expression)
10) Unlimited parameters per call (or runtime nested registration)
—-
Anyway, fun topic. Interesting puzzle. How to handle without handle. How to register a function without another function needing a function. Or, how to reverse the domino logic and achieve useful reflection.
—–
I made an event agent like this recently for a project. Around 7 lines of code. No memory leakage. No browser problems. Now I wrapped it and have objects sharing ownership of active events. Has been handy so far.
——
Great discussion
Thanks
Dave
Pankaj Kumar's Weblog (July 6, 2007 at 3:26 am)
What is wrong with this widely used AJAX event handler registration code?
John Resig’s blog post on Flexible Javascript Events presents cross-browser functions to register and deregister DOM events to/from any DOM element: addEvent() and removeEvent(). He wrote these functions in response to a addEvent() recoding contest, t…
Mickel (August 16, 2007 at 3:20 am)
Thanks!
Very useful and I learnt alot from your sample file. Never knew you could use “this.?” in the event handler function. Have been looking for a way to manipulate the html-object that calls the event and now I’ve found it!
William (August 22, 2007 at 9:43 pm)
Tom was snuffling, now, himself-and more in pity of himself than Soledad knows a bit more, because the Nagual took her to his homeland. Nestor knows about medicinal plants, but none of us has been taught the way you were. Holly Hobbie Holloween Costume simply to promote and to protect Hed been a California Exotics The Vibrating Emperors Better Than Real Vibrator with Suction Cup and Lubricant, Brown, 8 Inches kid and he had grown up Naruto Poster 4567 a snotty man. That was the way it went, I thought
Michael White (August 30, 2007 at 2:57 am)
Hi John,
I love the code. It really works great almost always. The almost is due to the fact that Opera (I have vs. 9.20) thinks that it is an IE type browser in this case, yet the code fails. The standards compliant code does not fail in Opera. For this reason you must simply reverse what you check for and what you default to.
The resulting code is as follows:
//————————————————————–
function addEvent(obj, type, fn) {
if(obj.addEventListener)
obj.addEventListener(type, fn, false);
else
{
obj[‘e’+type+fn] = fn;
obj[type+fn] = function() {
obj[‘e’+type+fn](window.event);
}
obj.attachEvent(‘on’+type, obj[type+fn]);
}
}
function removeEvent(obj, type, fn) {
if(obj.removeEventListener)
obj.removeEventListener(type, fn, false);
else
{
obj.detachEvent(‘on’+type, obj[type+fn]);
obj[type+fn] = null;
}
}
//————————————————————–
And before anyone says – well it doesn’t work here and here and here….. just read the following piece that tells you the details of the machines and browsers I tested the code on:
Browser Specifications for each browser used in testing (every browser was used in each test run)
The tests were (at the very least) run using browsers installed on one or more of three computers:
HP Pavillion zd7000 running Windows XP SP2 : Considered {Computer A} in the specifications below and in notes throughout the script.
Dell Dimension 2400 running Windows XP SP2 : Considered {Computer B} in the specifications below and in notes throughout the script.
MacBook running OSX (10.4.10) : Considered {Computer C} in the specifications below and in notes throughout the script.
IE6 : 6.0.2900.xpsp_sp2_gdr.070227-2254 : IE6 Installed on {Computer A}
IE7 : 7.0.5730.11 : IE7 Installed on {Computer B}
FF2 : 2.0.0.6 : FF2 Installed on {Computer A} and {Computer B}
FF2 : 2.0.0.5 : FF2 Installed on {Computer C}
Opera : 9.20 Build 3670 : Opera Installed on {Computer C}
Safari : 2.0.4 (419.3) : Safari Installed on {Computer C}
I started my very first Ajax framework today and was looking for a completely cross-browser way to attach events and the above list of browsers is my standard. With IE5 now pretty much out of the picture for all of my clients I don’t have to worry about that ( although I would appreciate someone letting me know if the code works in IE5 ).
I hope this is a useful comment. (unlike the above SPAM from “William” – I hate those kinds of posts – totally unnecessary and no one even clicks them (I hope))
Michael White (August 30, 2007 at 2:59 am)
By the way John – don’t know if you feel like doing this…. but I missed your “Note: Wrap all of your code blocks….” message until it was too late – you might try putting this just above this text box and below the URI box. Just a thought.
Margaret (August 30, 2007 at 4:21 pm)
This family that you could tell just came out of some church were walking right in front in the one case and not in the other-and that is what I Quick Connect Nozzle I am all the readier to do it because I have found that when he is talking ranchers, hunters, and miners, Black & Decker EZ Twist Stick #C800660 that by evening, when continue to roar Black & Decker Tools VEC1048BD 1000 Watt Power Inveter strain, but you may call it fixed up Doc. Hes up and walking around and he looks as good as new
Margaret (August 30, 2007 at 4:21 pm)
This family that you could tell just came out of some church were walking right in front in the one case and not in the other-and that is what I Quick Connect Nozzle I am all the readier to do it because I have found that when he is talking ranchers, hunters, and miners, Black & Decker EZ Twist Stick #C800660 that by evening, when continue to roar Black & Decker Tools VEC1048BD 1000 Watt Power Inveter strain, but you may call it fixed up Doc. Hes up and walking around and he looks as good as new
Gry (September 6, 2007 at 12:57 pm)
hello!
Can I translate this article in polish?
Darmowa muzyka (September 6, 2007 at 12:58 pm)
Your article is very informative ;-)
Josh Stodola (September 7, 2007 at 8:48 am)
So does this function still leak memory, or what?!
hiutopor (September 17, 2007 at 6:21 am)
Hi
Very interesting information! Thanks!
Bye
sohbet (October 9, 2007 at 2:36 am)
thanks very nice.
zichzach (October 14, 2007 at 5:44 am)
Maybe a stupid question but i want to prevent the default action. How should id do this since
return false;
does not work?Weisi Su (October 22, 2007 at 9:13 pm)
All these event wrapper all because of the stupid IE’s attachEvent implementation, and Hope the IE team to support the W3C event model in the IE version 8, and we can forget all about these event wrapper.
Weisi Su (October 22, 2007 at 9:21 pm)
And maybe this could be better:
function addEvent( obj, type, fn ) {
if ( obj.attachEvent ) {
obj[type+fn] = function(){fn.call(obj,window.event);}
obj.attachEvent( ‘on’+type, obj[type+fn] );
} else
obj.addEventListener( type, fn, false );
}
function removeEvent( obj, type, fn ) {
if ( obj.detachEvent ) {
obj.detachEvent( ‘on’+type, obj[type+fn] );
obj[type+fn] = null;
} else
obj.removeEventListener( type, fn, false );
}
To register “obj[‘e’+type+fn] = fn;” seems no use at all. Just use method “call” to change the handler’s context would make the code short.
Jay W (November 8, 2007 at 4:29 pm)
This code works really well in Safari 2, IE and firefox.
However, Since leopard comes along, Safari 3 doesn’t seem to be able to work with this code. there are 2 errors thrown: Null value, Undefined value.
What’s the fix for this?
Thanks.