views:

37

answers:

3

I have a site that uses AJAX to navigate. I have two pages that I use a click and drag feature using

$(".myDragArea").mousedown(function(){
  do stuff...
  mouseDrag = true; // mouseDrag is global.
});

$("body").mousemove(function(){
  if (mouseDrag) {
    do stuff...
  }
});

$("body").mouseup(function(){
  if (mouseDrag) {
    do stuff...
    mouseDrag = false;
  }
});

I just type that out, so excuse any incidental syntax errors. Two parts of the site use almost identical code, with the only difference being what is inside the $("body").mouseup() function. However, if I access the first part, then navigate to the second part, the code that runs on mouseup doesn't change. I have stepped through the code with firebug, and no errors or thrown when $("body").mouseup() is run when the second part loads.

So, why doesn't the event handler change when I run $("body").mouseup() the second time?

+1  A: 

Calling $("body").mouseup(function) will add an event handler.
You need to remove the existing handler by writing $("body").unbind('mouseup');.

SLaks
That is exactly what I needed. It's surprising that I haven't run into this problem yet - or maybe I have and I just haven't really realized it. Either way, thanks.
smfoote
A: 

jQUery doesn't "replace" event handlers when you wire up handlers.

If you're using Ajax to navigate, and not refreshing the overall DOM (i.e. not creating an entirely new body element on each request), then executing a new line like:

$("body").mouseup(function(){

is just going to add an additional handler. Your first handler will still exist.

You'll need to specifically remove any handlers by calling

$("body").unbind("mouseUp");
womp
I am using AJAX for navigation, so the DOM doesn't reload, so this is it. Thanks.
smfoote
+2  A: 

Using $("body").mouseup( ... ) will add an event handler for the body that is triggered at mouseup.

If you want to add another event handler that would conflict with current event handler(s) then you must first remove the current conflicting event handler(s).

You have 4 options to do this with .unbind(). I'll list them from the least precise to the most precise options:

  1. Nuclear option - Remove all event handlers from the body

    $("body").unbind();
    

    This is pretty crude. Let's try to improve.

  2. The elephant gun - Remove all mouseup event handlers from the body

    $("body").unbind('mouseup');
    

    This is a little better, but we can still be more precise.

  3. The surgeon's scalpel - Remove one specific event handler from the body

    $("body").unbind('mouseup', myMouseUpV1);    
    

    Of course for this version you must set a variable to your event handler. In your case this would look something like:

    myMouseUpV1 = function(){
      if (mouseDrag) {
        do stuff...
        mouseDrag = false;
      }
    }
    
    
    $("body").mouseup(myMouseUpV1);
    
    
    $("body").unbind('mouseup', myMouseUpV1);
    $("body").mouseup(myMouseUpV2); // where you've defined V2 somewhere
    
  4. Scalpel with anesthesia (ok, the analogy's wearing thin) - You can create namespaces for the event handlers you bind and unbind. You can use this technique to bind and unbind either anonymous functions or references to functions. For namespaces, you have to use the .bind() method directly instead of one of the shortcuts ( like .mouseover() ).
    To create a namespace:

    $("body").bind('mouseup.mySpace', function() { ... });
    

    or

    $("body").bind('mouseup.mySpace', myHandler);
    

    Then to unbind either of the previous examples, you would use:

    $("body").unbind('mouseup.mySpace');
    

    You can unbind multiple namespaced handlers at once by chaining them:

    $("body").unbind('mouseup.mySpace1.mySpace2.yourSpace');
    

    Finally, you can unbind all event handlers in a namespace irrespective of the event type!

    $("body").unbind('.mySpace')
    

    You cannot do this with a simple reference to a handler. $("body").unbind(myHandler) will not work, since with a simple reference to a handler you must specify the event type ( $("body").unbind('mouseup', myHandler) )!


PS: You can also unbind an event from within itself using .unbind(event). This could be useful if you want to trigger an event handler only a limited number of times.

var timesClicked = 0;
$('input').bind('click', function(event) {
  alert('Moar Cheezburgerz!');
  timesClicked++;
  if (timesClicked >= 2) {
    $('input').unbind(event);
    $('input').val("NO MOAR!");
  }
});​
Peter Ajtai
You missed namespaces.
SLaks
@SLaks - Thanks. Haven't used that technique before. I'll try and add it in.
Peter Ajtai