views:

603

answers:

3

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 by 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.

+1  A: 

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;
}
cmcculloh
This is a well-known idiom. It is neccessary if the event handler somehow triggers its own event and therefore gets invoked recursively, leading to infinite loop, rendering the browser unresponsive.But this is not my problem. I don't have unwanted recursion. My problem is that other event handlers interfere with my code, so I need to suppress event handling temporarily. The code of the other event handler is in BlockUI itself, so, no, I cannot modify it.
nalply
+1  A: 

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.

Reza
Yes, I used a block counter first. But $().ajaxStart($.blockUI).ajaxStop($.unblockUI) is neater - it does the blocking and unblocking for you, but will interfere like it happened to me in message().Please let's stick with the original question: how to suppress event handling temporarily. Perhaps in the sense of a suspend/resume mechanism.
nalply
+4  A: 

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"&gt;
<html xmlns="http://www.w3.org/1999/xhtml"&gt;
<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"&gt;&lt;/script&gt; 
<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>
andres descalzo
Wow! You wrote a small jQuery plugin! So you think that there is no easy trick to generally suspend/resume (or as you call freeze/unfreeze) event handling in jQuery?
nalply
reviewing the jQuery library, I saw it best to make this plugin. Must try to find out if you is useful
andres descalzo
How do freeze and unfreeze work? By the way, do you know the CopyEvents jQuery plugin? http://plugins.jquery.com/project/copyEvents
nalply
The plugin copy a functions to an array with the index "event type" and "handle" that is unique. then assigns a null function of the element to the event. when doing unfreezeevent, reassigns the functions found in the array.I do not know but I will get to investigate
andres descalzo