Sunday, June 10, 2012

How to find event listeners on a DOM node?


I have a page where some event listeners are attached to input boxes and select boxes. Is there a way to find out which event listeners are observing a particular DOM node and for what event?



Events are attached using 1) prototype's Event.observe 2) DOM's addEventListener 3) as element attribute element.onclick


Source: Tips4all

5 comments:

  1. If you just need to inspect what's happening on a page, you might try the Visual Event bookmarklet.

    ReplyDelete
  2. It depends on how the events are attached. For illustration presume we have the following click handler:

    var handler = function() { alert('clicked!') };


    We're going to attach it to our element using different methods, some which allow inspection and some that don't.

    Method A) single event handler

    element.onclick = handler;
    // inspect
    alert(element.onclick); // alerts "function() { alert('clicked!') }"


    Method B) multiple event handlers

    if(element.addEventListener) { // DOM standard
    element.addEventListener('click', handler, false)
    } else if(element.attachEvent) { // IE
    element.attachEvent('onclick', handler)
    }
    // cannot inspect element to find handlers


    Method C): jQuery

    $(element).click(handler);



    1.3.x

    // inspect
    var clickEvents = $(element).data("events").click;
    jQuery.each(clickEvents, function(key, value) {
    alert(value) // alerts "function() { alert('clicked!') }"
    })

    1.4.x (stores the handler inside an object)

    // inspect
    var clickEvents = $(element).data("events").click;
    jQuery.each(clickEvents, function(key, handlerObj) {
    alert(handlerObj.handler) // alerts "function() { alert('clicked!') }"
    // also available: handlerObj.type, handlerObj.namespace
    })



    (See jQuery.fn.data and jQuery.data)

    Method D): Prototype (messy)

    $(element).observe('click', handler);



    1.5.x

    // inspect
    Event.observers.each(function(item) {
    if(item[0] == element) {
    alert(item[2]) // alerts "function() { alert('clicked!') }"
    }
    })

    1.6 to 1.6.0.3, inclusive (got very difficult here)

    // inspect. "_eventId" is for < 1.6.0.3 while
    // "_prototypeEventID" was introduced in 1.6.0.3
    var clickEvents = Event.cache[element._eventId || (element._prototypeEventID || [])[0]].click;
    clickEvents.each(function(wrapper){
    alert(wrapper.handler) // alerts "function() { alert('clicked!') }"
    })

    1.6.1 (little better)

    // inspect
    var clickEvents = element.getStorage().get('prototype_event_registry').get('click');
    clickEvents.each(function(wrapper){
    alert(wrapper.handler) // alerts "function() { alert('clicked!') }"
    })

    ReplyDelete
  3. WebKit Inspector in Chrome or Safari browsers now does this. It will display the event listeners for a DOM element when you select it in the Elements pane.

    ReplyDelete
  4. It is possible to list all event listeners in javascript: Is not that hard; you just have to hack the prototype method of the HTML elements (before adding the listeners)

    function reportIn(e){
    var a = this.lastListenerInfo[this.lastListenerInfo.length-1];
    console.log(a)
    }


    HTMLAnchorElement.prototype.realAddEventListener = HTMLAnchorElement.prototype.addEventListener;

    HTMLAnchorElement.prototype.addEventListener = function(a,b,c){
    this.realAddEventListener(a,reportIn,c);
    this.realAddEventListener(a,b,c);
    if(!this.lastListenerInfo){ this.lastListenerInfo = new Array()};
    this.lastListenerInfo.push({a : a, b : b , c : c});
    };


    Now every anchor element ( < a > ) will have a 'lastListenerInfo' propierty wich contains all of its listeneres. And it even works for removing listeners with anonymous functions.

    ReplyDelete
  5. If you have Firebug, you can use console.dir(object or array) to print a nice tree in the console log of any javascript scalar, array, or object.
    Try:
    console.dir(clickEvents);
    or
    console.dir(window);

    ReplyDelete