194

Is it possible to determine whether an element has a click handler, or a change handler, or any kind of event handler bound to it using jQuery?

Furthermore, is it possible to determine how many click handlers (or whatever kind of event handlers) it has for a given type of event, and what functions are in the event handlers?

Mandeep Jain
  • 2,304
  • 4
  • 22
  • 38
Elias Zamaria
  • 96,623
  • 33
  • 114
  • 148

11 Answers11

141

You can get this information from the data cache.

For example, log them to the console (firebug, ie8):

console.dir( $('#someElementId').data('events') );

or iterate them:

jQuery.each($('#someElementId').data('events'), function(i, event){

    jQuery.each(event, function(i, handler){

        console.log( handler.toString() );

    });

});

Another way is you can use the following bookmarklet but obviously this does not help at runtime.

gotqn
  • 42,737
  • 46
  • 157
  • 243
redsquare
  • 78,161
  • 20
  • 151
  • 159
133

Killing off the binding when it does not exist yet is not the best solution but seems effective enough! The second time you ‘click’ you can know with certainty that it will not create a duplicate binding.

I therefore use die() or unbind() like this:

$("#someid").die("click").live("click",function(){...

or

$("#someid").unbind("click").bind("click",function(){...

or in recent jQuery versions:

$("#someid").off("click").on("click",function(){...
Dave Jarvis
  • 30,436
  • 41
  • 178
  • 315
SJG
  • 1,753
  • 1
  • 15
  • 10
  • 7
    +1 very neat even though it doesn't answer the question. – Zephyr was a Friend of Mine Nov 23 '11 at 20:41
  • This is the best way, and working way,, worked for me when other ways failed – Mazhar Ahmed Mar 27 '12 at 06:39
  • 7
    For jQuery 1.7 and later use `.off("click")` instead of `.die()` or `.unbind()` – David Clarke Aug 13 '13 at 23:01
  • This is a band aid. It's a better idea to find out why your code is executing twice and fix that bug. Or figure out where else the bind is being called and prevent it. – mattalxndr Feb 03 '14 at 03:38
  • Have to agree with @mattalxndr. At least use namespaces in such a case to avoid disabling events bound by unrelated code, like this: $("#someid").die("click.myPlugin").live("click.myPlugin",function(){... – Claus Conrad Sep 04 '14 at 11:09
  • 2
    I'd add that if you need to attach an event that only runs once and then removes itself, use the one() method. $("body").one("click",function(){ alert('test');}); – Daniel Katz Sep 09 '14 at 11:58
  • @SJG: Is it a safe approach? What if in the middle of re-binding operation (after `off`, but yet before `on`) an event is raised? The handler is not going to intercept it, is it? – jwaliszko Aug 29 '15 at 13:37
35

I wrote a plugin called hasEventListener which exactly does that :

http://github.com/sebastien-p/jquery.hasEventListener

Hope this helps.

Sebastien P.
  • 709
  • 7
  • 6
19

This solution is no more supported since jQuery 1.8 as we can read on the blog here:

$(element).data(“events”): This is now removed in 1.8, but you can still get to the events data for debugging purposes via $._data(element, "events"). Note that this is not a supported public interface; the actual data structures may change incompatibly from version to version.

So, you should unbind/rebind it or simply, use a boolean to determine if your event as been attached or not (which is in my opinion the best solution).

adriendenat
  • 3,445
  • 1
  • 25
  • 25
16

I think this might have updated with jQuery 1.9.*

I'm finding the this is the only thing that works for me at the moment:

$._data($("#yourElementID")[0]).events
jtromans
  • 4,183
  • 6
  • 35
  • 33
10

I wrote a very tiny plugin called "once" which do that:

$.fn.once = function(a, b) {
    return this.each(function() {
        $(this).off(a).on(a,b);
    });
};

And simply:

$(element).once('click', function(){
});
  • 2
    This seems to be identical to jQuery's own `.one` -- http://api.jquery.com/one/ -- which has been around since v1.1. Yours just has an extra "c" added in. – Luke Dec 12 '18 at 20:16
  • 1
    @Luke I know this is old, but you're wrong. As I understand it, this is different in that jQuery.one() allows the event to run (trigger) ONLY once before self-removing. This .once() function simply ensures that any existing handler is removed before binding the replacement (which can then trigger multiple times). Perhaps the function name is the confusing part, and perhaps better thought of as $.fn.replaceOn()? – Jon Bellamy Jun 22 '20 at 10:40
10

For jQuery 1.9+

var eventListeners = $._data($('.classname')[0], "events");

I needed the [0] array literal.

Union find
  • 7,759
  • 13
  • 60
  • 111
5

I don't think that the hasEventListener plugin mentioned will handle custom events e.g.

var obj = {id:'test'};
$(obj).bind('custom', function(){
    alert('custom');
}).trigger('custom');

alert($(obj).hasEventListener('custom'));

Also, at least in jQuery 1.5 I think you need to be careful using $(target).data('events') because it returns differently for events that have been bound to objects as above.

You need to do something like:

var events = $(target).data("events");
if(typeof events === "function"){
   events = events.events;
}

I am using this sort of approach and it works but it feels a bit like I am at the mercy of jquery internals and that really I shouldn't be doing it!

Julian Jelfs
  • 473
  • 6
  • 8
2

I had the same need & quickly patched an existing code to be able to do something like this:

 if( $('.scroll').hasHandlers('mouseout') )  // could be click, or '*'...
 { 
   ... code ..
 }

It works for event delegation too:

 if ( $('#main').hasHandlers('click','.simple-search') )  ...

It is available here : jquery-handler-toolkit.js

Nadir
  • 695
  • 8
  • 12
1

With reference to SJG's answer and from W3Schools.com

As of jQuery version 1.7, the off() method is the new replacement for the unbind(), die() and undelegate() methods. This method brings a lot of consistency to the API, and we recommend that you use this method, as it simplifies the jQuery code base.

This gives:

$("#someid").off("click").live("click",function(){...

or

$("#someid").off("click").bind("click",function(){...
Community
  • 1
  • 1
David Clarke
  • 12,888
  • 9
  • 86
  • 116
-6

This works for me: $('#profile1').attr('onclick')

Mike
  • 121
  • 1
  • 3
  • 9
  • 1
    it works only if a handler is attached via the "onclick" attribute. How about this case: `$('#profile1').click(function(){alert('')});`? `$('#profile1').attr('onclick')` returns `undefined`. – d.k Mar 29 '13 at 23:44