JavaScript from Null: Cross-Browser Event Binding
Tutorial Details
- Subject: JavaScript
- Estimated Difficulty: Beginner - Intermediate
- Tutorial Format: 29 Minute Screencast
Download Source Files
The Full Series
In chapter five of this series, we jumped into the muddy world of event listeners. In that episode, we only got our feet wet; however, today, we’ll take things a step further as we implement a far more efficient solution. Along the way, we’ll learn a plethora of new techniques.
As with every JavaScript from Null screencast, it’s not essential that you view the previous entries in the series before watching.
Chapter 6: Cross-Browser Event Binding
Premium Members: Download this Video ( Must be logged in)
Our Final Code
var addEvent = (function( window, document ) {
if ( document.addEventListener ) {
return function( elem, type, cb ) {
if ( (elem && !elem.length) || elem === window ) {
elem.addEventListener(type, cb, false );
}
else if ( elem && elem.length ) {
var len = elem.length;
for ( var i = 0; i < len; i++ ) {
addEvent( elem[i], type, cb );
}
}
};
}
else if ( document.attachEvent ) {
return function ( elem, type, cb ) {
if ( (elem && !elem.length) || elem === window ) {
elem.attachEvent( 'on' + type, function() { return cb.call(elem, window.event) } );
}
else if ( elem.length ) {
var len = elem.length;
for ( var i = 0; i < len; i++ ) {
addEvent( elem[i], type, cb );
}
}
};
}
})( this, document );
// Example Usage
var lis = document.getElementsByTagName('li');
addEvent( window, 'click', function() {
this.style.border = '1px solid red';
});
Please note that this code is slightly revised, based upon some excellent feedback in the comments section.

good tuts thanks a lot
I really enjoy these videos, thanks in advance.
Thank you soooooooooo much for continuing this series!!!
What did you use to create that content initially. Was it a sugar or a type of snippet?
It’s called Zen Coding.
Thank you for the sharing of articles of great and outstanding quality like this.
Figured it out! Very helpful tutorials!
Wow that was an awesome autofill function you have got for lorem!
cb.call() was a hard thing to understand. especially why you can use “this.” with IE.
I thought you would do something like
# function(e) {
# e.style.border = ’1px solid red’;
#
# });
Nice trick, thanks!
Hey Jeff! Thanks for these Videos! You know everyone enjoys them including me. Oh yeah, being a premium member on Tuts+ has helped A LOT! Thank you for all of the great tutorials and videos, it’s worth every penny! Thank you!
Hello Jeffrey,
Great video, it will surely help many people.
Going a bit off since I couldn’t find your e-mail:
Could you please send the TextMate theme you’re using (if it’s free) or the link to buy it ? It’s really cool!
Thank you,
bl00dshooter@hotmail.com.
Great tutorial as always !
Just one question: Is it better to use :
var myFunc = (function() {
});
rather than:
function myFunc() {
}
thanks in advance =)
The two code snippets above are different. I think you’re referring to:
var myFunc = function() { };Vs.
function myFunc() { }They essentially do the same thing; however, there are some high level benefits to using the first method.
Hi Jeffrey, is there a way to add a callback function when using the first method? It seems everywhere (including your own quicktip on the topic) people use the second method to teach how to add callback functions to a function definition.
Thanks.
Hey Hassan,
It’s the same process.
Thanks for this great video tutorial :)
I don`t understand why at the start you did something like that -
for ( var i = 0; i < len; i++ ) (function(i){ /*code*/ })(i);
Can Someone answer to the above question ??
I had the same question and was going nuts trying to figure it out. I eventually found the answer here:
http://www.mennovanslooten.nl/blog/post/62
I hope that helps!
Because, otherwise, the for loop will complete before the event is executed — resulting in a weird outcome. By implementing a closure (basically a function within a function), we can attach the current value of i.
Can be complicated stuff. I’ll plan on covering closures in more detail in a future episode.
Thanks jeff !
Looking forward to the closures episode.
Hey there, nice tut!
I can’t see why did you repeat yourself so many times in the code, it could be something like this:
function addEvent(elem, type, cb) {
if(elem) {
if(!elem.length) {
if(document.addEventListener)
elem.addEventListener(type, cb, false);
else if(document.attachEvent)
elem.attachEvent(‘on’ + type, function() { return cb.call(elem); } );
}
else {
var len = elem.length;
for(var i = 0; i < len; i++)
addEvent(elem[i], type, cb);
}
}
}
With your code, every single time you add an event listener, you first check for
document.addEventListener. Doesn’t that seem wasteful to perform that check for every event?I like your methods to increase script’s performance, in that one, and also when using length method in for loop :D
Nice tutorial.
Thanks for sharing.
Yay Chapter 6 is here waiting for chapter 7 :)
great tut, thanks Jeff for providing this series
Jeff i have a little problem in CSS and i just can’t solve it :( :
problem :(
a:focus div{
display:none;
}
problem
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere tempus adipiscing. Suspendisse volutpat vestibulum ante vitae consequat. Aliquam ultrices metus at urna tincidunt nec tincidunt felis adipiscing. Sed vel varius lacus. Curabitur eleifend laoreet justo, vitae bibendum libero tempus vel. Ut id mi orci. Donec orci erat, hendrerit sed auctor vitae, bibendum sit amet quam. In tristique enim vitae nibh hendrerit ac porttitor ante luctus. Phasellus hendrerit, lorem vitae porttitor dictum, ligula tellus porttitor metus, at pharetra elit lectus sed felis. Proin mattis tortor id orci cursus pellentesque vitae vel neque. Praesent facilisis arcu sed velit molestie pretium. Nam eu tempus ante. Integer lectus nulla, dignissim id dapibus sit amet, sollicitudin eget dolor. Aliquam sodales, metus faucibus fringilla ultrices, libero lacus suscipit lectus, a pulvinar mi leo a felis. Nullam rutrum tempus venenatis. Quisque ac lectus ut lacus accumsan porta imperdiet et leo. Aenean vel porta erat. Duis ultrices lectus sed nisl scelerisque feugiat. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus
like you see i have an “a” tag and a “div” tag, and what i want is :
i want when someone focus on the “a” tag i want to make the display off “div” is none to hide it
but it just didn’t work with me
if you have any idea on how to make this happen pleas tell me :(
and thanks
sorry about the previous comment here is the code:
(
problem :(
a:focus div{
display:none;
}
problem
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere tempus adipiscing. Suspendisse volutpat vestibulum ante vitae consequat. Aliquam ultrices metus at urna tincidunt nec tincidunt felis adipiscing. Sed vel varius lacus. Curabitur eleifend laoreet justo, vitae bibendum libero tempus vel. Ut id mi orci. Donec orci erat, hendrerit sed auctor vitae, bibendum sit amet quam. In tristique enim vitae nibh hendrerit ac porttitor ante luctus. Phasellus hendrerit, lorem vitae porttitor dictum, ligula tellus porttitor metus, at pharetra elit lectus sed felis. Proin mattis tortor id orci cursus pellentesque vitae vel neque. Praesent facilisis arcu sed velit molestie pretium. Nam eu tempus ante. Integer lectus nulla, dignissim id dapibus sit amet, sollicitudin eget dolor. Aliquam sodales, metus faucibus fringilla ultrices, libero lacus suscipit lectus, a pulvinar mi leo a felis. Nullam rutrum tempus venenatis. Quisque ac lectus ut lacus accumsan porta imperdiet et leo. Aenean vel porta erat. Duis ultrices lectus sed nisl scelerisque feugiat. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus
)
hope you get what i want to do
Well that is sooooo wired there is some thing wrong with this !!!
nevermined i uploaded the code for you to see it because every time i post the code here the wordpress show it like an html not a code, even when using !!!
here is the markup :
http://www.mediafire.com/?amb59gpvc0bah8x
I thought it was a little disappointing. By 2:40 you wrote:
“document.getElementsByTagName (‘l’). addEvent (‘”
so I’m was hoping that you will talk about some cross-browser prototype manipulation, which I have trouble with in one of my own projects.
Oh you’re right – I did do it that way for some reason. Sorry! Sometimes, I’m so busy talking that I make mindless errors like that. But yes, you’re right, to allow for that, you’d need to extend the object — which many consider to be a bad practice.
The method I taught in this video should work just fine.
It’s okay. I agree with you that this is bad style, especially if you are not very experienced in JavaScript which I do not think the primary audience of this article is quite yet.
Interesting article, thanks for posting!
Yeah, these tips are cool and awesome!
Thanks for sharing Jeff
Good article!!! i dont know much javascript… but these source files really help me alot..
Thanks for sharing
It’s wonderful for me!
Just to say thanks!
i like to play with using your tips. thanks for sharing
Hi Jeffrey,
Theres a couple of places where your code is wrong:
1) Testing for elem.length (or the lack thereof).
Example:
addEvent(window, hashchange, fn);
If there are any iframes in the document (as this tutorial page does) then when you test elem.length, its testing the window.length, which translates to window.frames.length. So in the case of this particular window, the length is 5 so the test would fail – and the code will fail.
2) Not such a big deal, but for cross browser event binding – pass the event in to IE attachEvent function, i.e.:
elem.attachEvent( on + type, function() { return cb.call(elem, window.event) } );
Hey Remy –
Oh good point on the iframes quirk. I almost never use them in my own projects, so that hasn’t been an issue for me, but you’re right. I’ll figure out the best way to compensate and update the code today. Hmm – I guess I could check if “elem” is not equal to “window,” or the other way around.
And good note about passing window.event to the callback. I covered the event object browsers issues and how to deal with them in the screencast. But, must have forgotten to update the code. I’ll do that one right now.
Thanks!
So I temporarily added:
to fix the window iframe issues. Those if statements are getting a bit bloated though. I’ll work on it some more after work.
If anyone else has some ideas, feel free to chime in.
Yet another great tutorial.
Keeps me wondering, why do some of the best tutorials out here come free? And in addition to that, why do some ( maybe most ) premium tuts perform the opposite?
Now, don`t me wrong, i love the free tuts! But why would you pay for premium content over this? This is really useful practical stuff! Why bother going premium if you get ( for example ) an explanation over the word “static”?
It may be usefull somehow, the premium content that is, but either provide true premium content, or ban the premium stuff. The price is rather high, and free content here is better then the premium stuf anyway.
All i`m trying to say is, either provide these articles as premium, for they contain truly usefull stuff, or stop posting premium stuff.
I`ve been following this site for almost 2 years now, and honestly, the content went down a lot.. In the beginning there was some very usefull content, how to create something simple as a cms for a photosite or how to build valid, good html/css. Good PHP articles and tutorials, and now it`s more and more the “quicktip” and roundups. A lot of advertising and promoting other envato sites. It`s a waste if you ask me, the content provided on this website used to be A++, now it`s more like A-..
Thanks!!
Thanks for sharing.
Hadn’t seen this question asked yet, so thought I’d go ahead and ask it.
Usually, when I go for cross-browser event binding in Javascript (of the normal events, not custom events), I aim for something like this:
myElement.onclick = function(){ alert(this.className);};
myElement.onfocus = function(){ this.cssStyle=”background-color:#000″; };
So far, it has seemed to work cross-browser, so what is the benefit of using the addEvent/eventListener approach here as opposed to that one? Also, if it does not work cross-browser (the approach I use), do you know in what instances it would not? Thanks!
The main problem with that method is that you can only attach one event handler at a time to each element. If you try to add another event listener that way, it will override the existing one.
As far as support, that method is actually very widely supported.
For all who are perplexed regarding closures, here’s a simple read regarding the topic
http://www.javascriptkit.com/javatutors/closures.shtml
Nice function Jeff :D, very efficient if your going to be adding lots of events…
Question…for the IE attachEvent, wouldn’t it make sense to add the argument for window.event, when you call the callback function? That way ‘e’ (or ‘evt’ or whatever you call the first argument) would be the Event object for IE, like it is for the modern browsers…
Example:
elem.attachEvent(‘on’ + type, function () {
return cb.call(elem, window.event);
});
Weird…I didn’t see that Remy already mentioned this…Please disregard
Thx 4 Sharing!
Hi Jeffrey,
Great tutorial!
But what I’m really impressed with are the snippets you are using.
Unfortunately I use windows for development (not mac) and I am interested if you are familiar with some solid tool for ‘smart’ code snippets(smart = not only static code, but possibility for variables… to accomplish similar what you’ve done in this screencast with ul->li items and lorem ipsum text).
I know you did a screencast on this before(and promoted texter, but I don’t like it cause it has too many bugs and doesn’t work nicely with all editors).
Keep on doing a great job!
Thanks,
Bye!
Hi Jeff,
Firstly, great tutorials. You have a gift for making the complex simple.
On that note, I think your loyal “Javascript From Null” followers would greatly benefit from a short tut on JS closures. Having looked over some of the top Google hits on the subject, it became apparent that it is an advanced topic – at least in understanding the nuances.
I am the type of person, however bad it might be, that can get hung up on any part of a tut that I may not fully grasp. While I know that rabbit trailing into all the minutiae of your tuts wouldn’t be productive, I think explaining closures sooner would help.
Thanks again!
Hey Alex – You’re absolutely right. Closures will be the topic for the next JS from Null episode. I realized after I threw that for statement / function trick into the mix…that it would confuse a lot of people.
So, pretty soon! I’m at a Envato team meet-up in Chicago this week, but as soon as I get back, I’m recording it!
gracias, te apuntas otra jefrry
Hi Jeffrey! Please go on with this tutorials!
Hey Jeff, I’ve just completed watching all the JS from null tutorials and man are they great! I definitely have a better understanding of raw JS and when I’ll be manipulating JS libraries.
However I have a concern in line 20 of you code that compensates for IE you wrote:
else if ( elem.length ) {/*code*/}
and not
else if ( elem && elem.length ) {/*code*/}
I might answer my own question here, but I liked to get some “closure” (get it!). Would a single element or in this example the list item still retain a length even if it is the only list item in an unordered list for IE or modern browsers? And do modern browsers have to require the elem && elem.length arguments to have this function work?
Chapter 7 please!
Added some Content to check if Document is Loaded
//For FF:
return function(elem, type, cb){
if(type == ‘ready’){
document.addEventListener(“DOMContentLoaded”,cb,false);
}
if(elem && !elem.length){….. jeff’s code
//For IE:
return function(elem, type, cb){
if(type == ‘ready’){
document.write(“”);
document.getElementById(“DOMReady”).onreadystatechange=cb
}
if(elem && !elem.length){… jeff’s code
to load the function use:
var a = document.getElementById(‘h’)
addEvent(document, ‘ready’, function(){
document.getElementById(‘h’).style.background = ‘red’;
});
But For IE there is only a “document” load, in FF you also can use “window”, ‘ready’
sry for double posting:
the IE version can also be:
if(type == ‘load’){
window.attachEvent(‘on’ + type, cb);
}
–> we dont need to add a own funciton for ie
for FF
if(type == ‘load’){
document.addEventListener(“DOMContentLoaded”,cb,false);
}
use it like this:
addEvent(document, ‘load’, function(){
document.getElementById(‘h’).style.background = ‘red’;
});
When in your next video going to be available.
Hi Jeffrey! thanks for this great series.
however i do have a problem: when i add the code the same way but only with removing and detaching .
when i use something like: document.getElementsByTagName(‘li’)[0], and try to detach events from this elemnt, its keep adding events (?) only in IE. with getElementById it works fine. any Idea?
Thank you for this great tutorial!
The question:
Is there a way to pass parameters to the Callback function when using this addEvent function?
For example:
addEvent(element, ‘mouseover’, changeColor(‘green’))
where the callback function looks something like this:
function changeColor (color) {
element.style.backgroundColor = color;
}
In the firebug console this sort of code returns:
“uncaught exception: [Exception… “Could not convert JavaScript argument” nsresult: “0×80570009 (NS_ERROR_XPC_BAD_CONVERT_JS)” ”
When I change the changeColor(‘green’) function in “addEvent(element, ‘mouseover’, changeColor(‘green’))” to simply “changeColor” and hardcode the color green in to the callback function, the code works.
When using inline event handlers the same sort of code works all right, and you actually can pass parameters to the function (‘yellow’):
come text
Thank you.
Hi Jefrrey,
Really good post!
I got one question:
What is the best way to add a “change” event to a “select element”.
“select elements” has length and it add “change” event to “select > options” as well, and “change” event is not fired.
Sorry my poor English,
thanks for the great to tutorial
Hey jeff, are you still planning on doing a tutorial on closures?
The Video starts for a few seconds and then stops :s
Hi there,
I copied the revised script in my markup, opened it in FF 3.6 and now I get the error
this.style is undefined
this.style.border = ’1px solid red’;
Any idea, what went wrong?
I was working with this event listener function and was unable to get the following working:
How would I do that?
oops, didn’t search/replace:
<input type=’submit’ name=’submit’ value=’Go’ />
Good tut. Have a question. I can’t figure out why we need to return the cb.call() result ( ie case ) and not just .call() it inside an anonymous function. It’s undefined until callback returns something else. Does IE need that value for any reason? What I’m referring to:
elem.attachEvent( ‘on’ + type, function() { cb.call(elem, window.event) } );
Hi,
I can’t get var li = document.getElementById() (or Tagname) to work unless they are in a function what am I doing wrong?
command prompt in Firefox reports that document.getElementById() does produce a value however var li = document.getElementById() (or Tagname) is undefined
Cheers
Andy
School boy error…the script simply needs to be below the HTML