JavaScript from Null: Cross-Browser Event Binding
basixvideos

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»

Add Comment

Discussion 72 Comments

Comment Page 1 of 21 2
  1. esranull says:

    good tuts thanks a lot

  2. I really enjoy these videos, thanks in advance.

  3. Etrimon says:

    Thank you soooooooooo much for continuing this series!!!

  4. Adam says:

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

  5. Pablo Lara H says:

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

  6. Adam says:

    Figured it out! Very helpful tutorials!

  7. Max says:

    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!

  8. kawohi says:

    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!

  9. Eduardo Barros says:

    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.

  10. herpderp says:

    Great tutorial as always !

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

    });

    rather than:
    function myFunc() {

    }

    thanks in advance =)

    • Jeffrey Way says:

      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 says:

        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.

      • Jeffrey Way says:

        Hey Hassan,

        It’s the same process.

  11. Yosy says:

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

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

  13. Jaspal Singh says:

    Nice tutorial.
    Thanks for sharing.

  14. Ahmed CZ says:

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

  15. Ahmed CZ says:

    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

  16. Ahmed CZ says:

    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

  17. Ahmed CZ says:

    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

  18. Andreas Madsen says:

    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.

    • Jeffrey Way says:

      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 says:

        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.

  19. GKL says:

    Interesting article, thanks for posting!

  20. Yeah, these tips are cool and awesome!

  21. DesignMango says:

    Thanks for sharing Jeff

  22. imran khan says:

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

    Thanks for sharing

  23. Kam says:

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

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

  25. Remy Sharp says:

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

    • Jeffrey Way says:
      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!

      • Jeffrey Way says:
        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.

  26. James says:

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

  27. Gabriel Cunha says:

    Thanks!!
    Thanks for sharing.

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

  29. Xander says:

    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…

  30. Rob Henry says:

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

  31. Dionis says:

    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!

  32. Alex says:

    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!

    • Jeffrey Way says:
      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!

  33. chichibek says:

    gracias, te apuntas otra jefrry

  34. Andrei Dorin says:

    Hi Jeffrey! Please go on with this tutorials!

  35. Andre Dublin says:

    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?

  36. Danielson says:

    Chapter 7 please!

  37. Michael says:

    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’

  38. Michael says:

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

  39. James Fair says:

    When in your next video going to be available.

  40. Yoav says:

    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?

  41. Ivan says:

    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.

  42. Alysson Bortoli says:

    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

  43. Arturo says:

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

  44. Marco says:

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

  45. jackie says:

    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?

  46. Josh says:

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

    How would I do that?

  47. Josh says:

    oops, didn’t search/replace:

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

  48. Zlatev says:

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

  49. Andy says:

    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

Comment Page 1 of 21 2

Add a Comment

To add a code snippet to your comment, please wrap your code like so: <pre name="code" class="html">YOUR CODE</pre>. You can replace the class name with "js," "css," "sql," or "php." If there are any "<" or ">" within your code, please search and replace them with: &lt; and &gt; respectively.