开发者

Suppress jQuery event handling temporarily

开发者 https://www.devze.com 2022-12-12 12:59 出处:网络
Is there an elegant way to temporarily suppress jQuery events? I use code like this: $(element).unbind(event, function1).unbind(event, function2);

Is there an elegant way to temporarily suppress jQuery events? I use code like this:

$(element).unbind(event, function1).unbind(event, function2);
// code for which the event is suppressed
$(element).bind(event, function1).bind(event, function2);

but I find it a bit clumsy and not very scalable to many events. Why do I want to suppress events temporarily? I use BlockUI plugin to block UI during Ajax access. This is done with: $().ajaxStart($.blockUI).ajaxStop($.unblockUI) as proposed b开发者_StackOverflow中文版y BlockUI.

However, one Ajax access is special, so I need a different message. The ajaxStart and ajaxStop events interfere with the message code (nothing is shown):

function message(text, callback) {
  if (text == undefined) {
     $.unblockUI();
     return;
  }

  // $().unbind('ajaxStop', $.unblockUI).unbind('ajaxStart', $.blockUI);
  $("#message_text").html(text);
  $.blockUI({message: $("#message")});
  $("#message_ok").click(function() { 
    // $().bind('ajaxStop', $.unblockUI).bind('ajaxStart', $.blockUI);
    $.unblockUI();
    if (callback != undefined) callback();
  });
}

Only if I uncomment the unbind() and the bind() lines, it is working.


I realize this question is old, but I found it while seeking an answer to the same question, and ended up finding a different solution that works well in simple applications of event handlers.

$(element).click(function(e) {
  e.preventDefault();

  // Check for fired class
  if ($(this).hasClass('fired') == false) {
     // Add fired class to all instances of element
     $(element).addClass('fired');

     // Do the rest of the function...

     // Remove fired class to 'reactivate' events
     $(element).removeClass('fired');   
  }
}

Simply adding a class to your 'element's while the code from the event is firing allows you to prevent further code from being executed as the result of another click event. So while you're not actually preventing any other click events, you're preventing the resulting code from running. Simple, crude, ignores the heavily preached use of bind and unbind, but works.


cost me finish this script, I hope it's useful:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script> 
<script type="text/javascript">
$(function(){

    //ini plugin

    jQuery.event.freezeEvents = function(elem) {

        if (typeof(jQuery._funcFreeze)=="undefined")
            jQuery._funcFreeze = [];

        if (typeof(jQuery._funcNull)=="undefined")
            jQuery._funcNull = function(){ };

        // don't do events on text and comment nodes
        if ( elem.nodeType == 3 || elem.nodeType == 8 )
            return;

        var events = jQuery.data(elem, "events"), ret, index;

        if ( events ) {

            for ( var type in events )
            {
                if ( events[type] ) {

                    var namespaces = type.split(".");
                    type = namespaces.shift();
                    var namespace = RegExp("(^|\\.)" + namespaces.slice().sort().join(".*\\.") + "(\\.|$)");

                    for ( var handle in events[type] )
                        if ( namespace.test(events[type][handle].type) ){
                            if (events[type][handle] != jQuery._funcNull){
                                jQuery._funcFreeze["events_freeze_" + handle] = events[type][handle];
                                events[type][handle] = jQuery._funcNull;
                            }
                        }
                }

            }
        }
    }

    jQuery.event.unFreezeEvents = function(elem) {

        // don't do events on text and comment nodes
        if ( elem.nodeType == 3 || elem.nodeType == 8 )
            return;

        var events = jQuery.data(elem, "events"), ret, index;

        if ( events ) {

            for ( var type in events )
            {
                if ( events[type] ) {

                    var namespaces = type.split(".");
                    type = namespaces.shift();

                    for ( var handle in events[type] )
                        if (events[type][handle]==jQuery._funcNull)
                            events[type][handle] = jQuery._funcFreeze["events_freeze_" + handle];

                }
            }
        }
    }

    jQuery.fn.freezeEvents = function() {

        return this.each(function(){
            jQuery.event.freezeEvents(this);
        });

    };

    jQuery.fn.unFreezeEvents = function() {

        return this.each(function(){
            jQuery.event.unFreezeEvents(this);
        });

    };

    //end plugin

    jQuery("#test1").ajaxStart(function test1(){
        jQuery("#result").append('test1 ajaxStop<br>');
    });

    jQuery("#test1").ajaxStop(function test2(){
        jQuery("#result").append('test1 click<br>');
    });

    jQuery("#test1").bind("click", function test3(){
        jQuery("#result").append('test1 click<br>');
    });

    jQuery("#test2").bind("click", function test5(){
        jQuery("#result").append('test2 click<br>');
    });

    jQuery("#freez").click(function(){
        jQuery("#test1").freezeEvents();
        jQuery("#test2").freezeEvents();
    });

    jQuery("#unfreez").click(function(){
        jQuery("#test1").unFreezeEvents();
        jQuery("#test2").unFreezeEvents();
    });

});
</script>
</head>
<body>
<button id="freez">freez</button>
<button id="unfreez">un freez</button>
<br />
<div id="test1">test1 click mousemove</div>
<div id="test2">test2 click mousemove</div>
<br />
<div id="result"></div>
</body>
</html>


The simplest way to do this is to add a check at the beginning of the bound method to determine if the method should run. If not, simply return from the method.

var doThing = true;

$("#foo").bind("click", function(e) {
    if(!doThing){return;}
    //do thing
}

function bar(){
    //temp unbind click
    doThing = false;

    //do stuff...

    //rebind click
    doThing = true;
}


I really liked Andres' approach to this problem, but it appears that since he came up with that code, the jQuery event model has changed, so in recent versions of jQuery his code doesn't work. Here it is modernised. Tested (lightly) in 1.8.2:

$.event.freezeEvents = function(elem) {

        if (typeof($._funcFreeze)=="undefined") {
            $._funcFreeze = [];
        }

        if (typeof($._funcNull)=="undefined") {
            $._funcNull = function() {};
        }                

        // don't do events on text and comment nodes
        if ( elem.nodeType == 3 || elem.nodeType == 8 ) {
            return;
        }

        var events = $._data(elem, "events");

        if (events) {
            $.each(events, function(type, definition) {
                $.each(definition, function(index, event) {
                    if (event.handler != $._funcNull){
                        $._funcFreeze["events_freeze_" + event.guid] = event.handler;
                        event.handler = $._funcNull;
                    }
                })
            })
        }
    }

    $.event.unFreezeEvents = function(elem) {

        // don't do events on text and comment nodes
        if ( elem.nodeType == 3 || elem.nodeType == 8 )
                return;

        var events = $._data(elem, "events");

        if (events) {
            $.each(events, function(type, definition) {
                $.each(definition, function(index, event) {
                    if (event.handler == $._funcNull){
                        event.handler = $._funcFreeze["events_freeze_" + event.guid];
                    }
                })
            })
        }
    }

    $.fn.freezeEvents = function() {
        return this.each(function(){
            $.event.freezeEvents(this);
        });
    };

    $.fn.unFreezeEvents = function() {
        return this.each(function(){
            $.event.unFreezeEvents(this);
        });
    };

I haven't tested this beyond an element with two events, but it works fine for me. Hope this helps someone.


You can simply save and restore the entire events object:

var events=$._data(elem, 'events'); // save events
$._data(elem, 'events', {}); // cancel all events
// any code here will not fire events
$._data(elem, 'events', events); // restore events

This worked for me but may have unknown side effects ...


So is the idea to block the page, fire multiple ajax requests (chained or otherwise) and then unblock the page?

If that is the case (and I've understood the question correctly) then you could use a block counter?

e.g. var blockcounter = 0;

function block(){
if(blockcounter==0)
 {$.blockUI({message: "Hai", showOverlay:true});}
blockcounter++;
}

function unblock(){
blockcounter--;
if(blockcounter==0)
{$.unblockUI();}
}

then in your code

function dostuff(){
block();
... do whatever ajax you need
... call unblock() in the success event of your ajax call
}

function dostuff2(){
block();
... do some more ajax - this might take a bit longer to complete though
... call unblock() in the success event
}

dostuff();
dostuff2();

Blocking should occur once only then and you're free to do whatever in the middle.

I use this method successfully on a website where there are multiple events happening between blocking and unblocking and where the different ajax events can complete in varying times. If you wrap the whole lot up in a namespace you can also avoid littering the place with global vars.

0

精彩评论

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