开发者

How to check if click event is already bound - JQuery

I am binding a click event with a button:

$('#myButton').bind('click',  onButtonClicked);

In one scenario, this i开发者_运维技巧s getting called multiple times, so when I do a trigger I see multiple ajax calls which I want to prevent.

How do I bind only if its not bound before.


One more way - mark such buttons with a CSS class and filter:

$('#myButton:not(.bound)').addClass('bound').bind('click',  onButtonClicked);

In recent jQuery versions replace bind with on:

$('#myButton:not(.bound)').addClass('bound').on('click',  onButtonClicked);


Update 24 Aug '12: In jQuery 1.8, it is no longer possible to access the element's events using .data('events'). (See this bug for details.) It is possible to access the same data with jQuery._data(elem, 'events'), an internal data structure, which is undocumented and therefore not 100% guaranteed to remain stable. This shouldn't, however, be a problem, and the relevant line of the plugin code above can be changed to the following:

var data = jQuery._data(this[0], 'events')[type];

jQuery events are stored in a data object called events, so you could search in this:

var button = $('#myButton');
if (-1 !== $.inArray(onButtonClicked, button.data('events').click)) {
    button.click(onButtonClicked);
}

It would be best, of course, if you could structure your application so this code only gets called once.


This could be encapsulated into a plugin:

$.fn.isBound = function(type, fn) {
    var data = this.data('events')[type];

    if (data === undefined || data.length === 0) {
        return false;
    }

    return (-1 !== $.inArray(fn, data));
};

You could then call:

var button = $('#myButton');
if (!button.isBound('click', onButtonClicked)) {
    button.click(onButtonClicked);
}


If using jQuery 1.7+:

You can call off before on:

$('#myButton').off('click', onButtonClicked) // remove handler
              .on('click', onButtonClicked); // add handler

If not:

You can just unbind it first event:

$('#myButton').unbind('click', onButtonClicked) //remove handler
              .bind('click', onButtonClicked);  //add handler


I wrote a very tiny plugin called "once" which do that. Execute off and on in element.

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

And simply:

$(element).once('click', function(){
});


The best way I see is to use live() or delegate() to capture the event in a parent and not in each child element.

If your button is inside a #parent element, you can replace:

$('#myButton').bind('click', onButtonClicked);

by

$('#parent').delegate('#myButton', 'click', onButtonClicked);

even if #myButton doesn't exist yet when this code is executed.


Why not use this

unbind() before bind()

$('#myButton').unbind().bind('click',  onButtonClicked);


Here's my version:

Utils.eventBoundToFunction = function (element, eventType, fCallback) {
    if (!element || !element.data('events') || !element.data('events')[eventType] || !fCallback) {
        return false;
    }

    for (runner in element.data('events')[eventType]) {
        if (element.data('events')[eventType][runner].handler == fCallback) {
            return true;
        }

    }

    return false;
};

Usage:

Utils.eventBoundToFunction(okButton, 'click', handleOkButtonFunction)


To avoid to check/bind/unbind, you can change your approach! Why don't you use Jquery .on() ?

Since Jquery 1.7, .live(), .delegate() is deprecated, now you can use .on() to

Attach an event handler for all elements which match the current selector, now and in the future

It means that you can attach an event to a parent element that is still existing and attach children elements whether they are present or not!

When you use .on() like this:

$('#Parent').on('click', '#myButton'  onButtonClicked);

You catch event click on parent and it search child '#myButton' if exists...

So when you remove or add a child element, you do not have to worry about whether to add or remove the event binding.


Based on @konrad-garus answer, but using data, since I believe class should be used mostly for styling.

if (!el.data("bound")) {
  el.data("bound", true);
  el.on("event", function(e) { ... });
}


Try:

if (typeof($("#myButton").click) != "function") 
{
   $("#myButton").click(onButtonClicked);
}


if ($("#btn").data('events') != undefined && $("#btn").data('events').click != undefined) {
    //do nothing as the click event is already there
} else {
    $("#btn").click(function (e) {
        alert('test');
    });
}


As of June 2019, I've updated the function (and it's working for what I need)

$.fn.isBound = function (type) {
    var data = $._data($(this)[0], 'events');

    if (data[type] === undefined || data.length === 0) {
        return false;
    }
    return true;
};


JQuery has solution:

$( "#foo" ).one( "click", function() {
  alert( "This will be displayed only once." );
}); 

equivalent:

$( "#foo" ).on( "click", function( event ) {
  alert( "This will be displayed only once." );
  $( this ).off( event );
});
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜