Try Tuts+ Premium, Get Cash Back!
JavaScript from Null: Cross-Browser Event Binding
videos

JavaScript from Null: Cross-Browser Event Binding

Tutorial Details
  • Subject: JavaScript
  • Estimated Difficulty: Beginner - Intermediate
  • Tutorial Format: 29 Minute Screencast
Download Source Files
This entry is part 6 of 7 in the series javascript-from-null

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.

Series Navigation«JavaScript from Null: Chapter 5 – EventsJavaScript from Null: Utility Functions and Debugging»

Tags: Videos
Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • http://laroouse.com esranull

    good tuts thanks a lot

  • http://www.facebook.com/Dev.MZahran Mohamed Zahran

    I really enjoy these videos, thanks in advance.

  • Etrimon

    Thank you soooooooooo much for continuing this series!!!

  • Adam

    What did you use to create that content initially. Was it a sugar or a type of snippet?

    • http://www.jeffrey-way.com Jeffrey Way
      Author

      It’s called Zen Coding.

  • http:/pablolarah.cl/ Pablo Lara H

    Thank you for the sharing of articles of great and outstanding quality like this.

  • Adam

    Figured it out! Very helpful tutorials!

  • Max

    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!

  • kawohi

    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!

  • Eduardo Barros

    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.

  • herpderp

    Great tutorial as always !

    Just one question: Is it better to use :
    var myFunc = (function() {

    });

    rather than:
    function myFunc() {

    }

    thanks in advance =)

    • http://net.tutsplus.com Jeffrey Way

      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.

      • Hassan

        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.

      • http://net.tutsplus.com Jeffrey Way

        Hey Hassan,

        It’s the same process.

  • Yosy

    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);

    • RockStar

      Can Someone answer to the above question ??

    • http://www.jenileigh.com Jen Kelly

      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!

    • http://www.jeffrey-way.com Jeffrey Way
      Author

      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.

      • RockStar

        Thanks jeff !

      • Kurt

        Looking forward to the closures episode.

  • http://shay.co/ Shay Ben Moshe

    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);
    }
    }
    }

    • http://www.jeffrey-way.com Jeffrey Way
      Author

      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?

      • http://www.facebook.com/Dev.MZahran Mohamed Zahran

        I like your methods to increase script’s performance, in that one, and also when using length method in for loop :D

  • http://www.jsxtech.com Jaspal Singh

    Nice tutorial.
    Thanks for sharing.

  • http://Byte-News.com Ahmed CZ

    Yay Chapter 6 is here waiting for chapter 7 :)
    great tut, thanks Jeff for providing this series

  • http://Byte-News.com Ahmed CZ

    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

  • http://Byte-News.com Ahmed CZ

    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

  • http://Byte-News.com Ahmed CZ

    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

  • Andreas Madsen

    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.

    • http://net.tutsplus.com Jeffrey Way

      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.

      • Andreas Madsen

        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.

  • http://www.web30textures.com/ GKL

    Interesting article, thanks for posting!

  • http://thedevelopertuts.com thedevelopertuts

    Yeah, these tips are cool and awesome!

  • http://www.designmango.com DesignMango

    Thanks for sharing Jeff

  • http://www.websolpk.com imran khan

    Good article!!! i dont know much javascript… but these source files really help me alot..

    Thanks for sharing

  • http://www.silverjewelryworld.com Kam

    It’s wonderful for me!
    Just to say thanks!

  • http://www.tutoriallounge.com Tutorial Lounge

    i like to play with using your tips. thanks for sharing

  • http://twitter.com/rem Remy Sharp

    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) } );

    • http://www.jeffrey-way.com Jeffrey Way
      Author

      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!

      • http://www.jeffrey-way.com Jeffrey Way
        Author

        So I temporarily added:

        if ( (elem && !elem.length) || elem === window ) 
        

        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.

  • James

    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-..

  • Gabriel Cunha

    Thanks!!
    Thanks for sharing.

  • http://www.isaacvanname.com Isaac Van Name

    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!

    • http://www.ultramegatech.com/ Steve Guidetti

      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.

  • http://xandercs.com Xander

    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…

  • Rob Henry

    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);
    });

    • Rob Henry

      Weird…I didn’t see that Remy already mentioned this…Please disregard

  • http://holamiamor.tistory.com Irene

    Thx 4 Sharing!

  • Dionis

    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!

  • Alex

    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!

    • http://www.jeffrey-way.com Jeffrey Way
      Author

      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!

  • chichibek

    gracias, te apuntas otra jefrry

  • http://www.webcome.ro Andrei Dorin

    Hi Jeffrey! Please go on with this tutorials!

  • Andre Dublin

    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?

  • Danielson

    Chapter 7 please!

  • Michael

    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’

  • Michael

    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’;
    });

  • James Fair

    When in your next video going to be available.

  • Yoav

    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?

  • Ivan

    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.

  • Alysson Bortoli

    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

  • Arturo

    Hey jeff, are you still planning on doing a tutorial on closures?

  • http://twitter.com/_jamonn Marco

    The Video starts for a few seconds and then stops :s

  • jackie

    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?

  • Josh

    I was working with this event listener function and was unable to get the following working:

    How would I do that?

  • Josh

    oops, didn’t search/replace:

    <input type=’submit’ name=’submit’ value=’Go’ />

  • Zlatev

    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) } );

  • Andy

    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

    • Andy

      School boy error…the script simply needs to be below the HTML