0

I need a CrossBrowser-EventListener in pure Javascript.

On the internet I found the following 2 versions.

Which one is the right / better one?

Could someone please explain the SECOND version?

(especially this paragraph is not clear to me: event_function.call(html_element);

Version 1:

function AddEvent(html_element, event_name, event_function) 
{       
   if(html_element.attachEvent) //Internet Explorer
      html_element.attachEvent("on" + event_name, event_function); 
   else if(html_element.addEventListener) // Everything else
      html_element.addEventListener(event_name, event_function, false);
}

Version 2:

function AddEvent(html_element, event_name, event_function) 
{       
   if(html_element.attachEvent) //Internet Explorer
      html_element.attachEvent("on" + event_name, function() { event_function.call(html_element); }); //<-- This I don't understand
   else if(html_element.addEventListener) // Everything else
      html_element.addEventListener(event_name, event_function, false);
}
  • Just use [`Element.addEventListener()`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener) for anything but IE8 and less. If you really need to support IE8 (and less) then check the [Compatibility section](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Compatibility) – Andreas Oct 29 '15 at 11:51
  • Neither of them does a thorough job of cross-browser handling. – T.J. Crowder Oct 29 '15 at 11:54

1 Answers1

2

Preface: All modern browsers support addEventListener, even IE9+, with the caveat that IE9-IE11 will hobble themselves by default via (in)Compatibility Mode on intranet sets and (I think) in some other contexts. You can tell IE9-IE11 not to hobble themselves by sending the X-UA-Compatible header from the server, or including it as a meta tag at the beginning of head. (This answer claims you actually have to send it from the server, but I believe it's incorrect; it's just that if you put the meta tag further down, IE may ignore it.) So unless you need to support IE8, you probably don't need a cross-browser alternative anymore.


Neither of them does a thorough job of normalizing what the event handler deals with.

The differences you need to handle are:

  • The value of this when calling the handler

  • Where the event object comes from

  • The methods available on the event object

The part you don't understand:

html_element.attachEvent("on" + event_name, function() { event_function.call(html_element); }); //<-- This I don't understand

...is trying to handle the first of those, the value of this within the callback. Function#call calls a function allowing you to set a specific value for this to have during the call. So event_function.call(html_element) calls event_function with this equal to html_element.

Some time back, for this answer, I wrote this which does a fairly thorough job:

var hookEvent = (function() {
    var div;

    // The function we use on standard-compliant browsers
    function standardHookEvent(element, eventName, handler) {
        element.addEventListener(eventName, handler, false);
        return element;
    }

    // The function we use on browsers with the previous Microsoft-specific mechanism
    function oldIEHookEvent(element, eventName, handler) {
        element.attachEvent("on" + eventName, function(e) {
            e = e || window.event;
            e.preventDefault = oldIEPreventDefault;
            e.stopPropagation = oldIEStopPropagation;
            handler.call(element, e);
        });
        return element;
    }

    // Polyfill for preventDefault on old IE
    function oldIEPreventDefault() {
        this.returnValue = false;
    }

    // Polyfill for stopPropagation on old IE
    function oldIEStopPropagation() {
        this.cancelBubble = true;
    }

    // Return the appropriate function; we don't rely on document.body
    // here just in case someone wants to use this within the head
    div = document.createElement('div');
    if (div.addEventListener) {
        div = undefined;
        return standardHookEvent;
    }
    if (div.attachEvent) {
        div = undefined;
        return oldIEHookEvent;
    }
    throw "Neither modern event mechanism (addEventListener nor attachEvent) is supported by this browser.";
})();

Then you'd use it like this in your example:

hookEvent(document.getElementById("hd_vertical"), "click", function(e) {
    // ...
});
Community
  • 1
  • 1
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Thanks a lot! This is really AWESOME! Could you perhaps also provide code for a REMOVEListener-Function? Because I don't know how to rearrange your oldIEHookEvent-Function in a REMOVEListener. – Manny_user3297459 Oct 29 '15 at 12:31
  • @user3297459: That's true, the above doesn't make any provision for *removing* listeners. There are lots of ways to do that. The way `removeEventListener` works is actually a bit of a pain to emulate; you basically have to do what jQuery does: Hook the event once for your library, store a list of handlers that have been registered, and fire them yourself if the event occurs. Then you have the info you need to remove one. That's fairly complex. The above could very simply return a function that would let you remove the listener you just added, but that's using different semantics. – T.J. Crowder Oct 29 '15 at 12:47
  • Yeah, that's what I thought. Thank anyway. So I'm probably going to build a set of function using your logic plus an EventCache like Dustin Diaz did in his "rock Solid addEvent" plus my own removeListener-Function which uses the cache to remove the Listener. But again: THANKS A LOT! You really helped me! – Manny_user3297459 Oct 29 '15 at 13:41