Jquery, unbinding mousewheel event, then rebinding it after actions are completed?

Rick picture Rick · Jul 26, 2010 · Viewed 16.2k times · Source

I've been struggling with this for a little while now.. I am using this code to monitor the mousewheel so it can be used for scrolling with a slider that I have.. however, it has an issue where the actions queue up so if you scroll with the mousewheel fast (like anyone would do normally) they build up and it causes buggy behavior.. I know about handling this sort of issue with animation, but not with a mousewheel monitor..

I want to do something like unbind the mousewheel at the start of the action (in this case, to scroll the scrollbar after mousewheel is moved) then rebind it after this, so if user does too many scrolls too fast it just ignores until the initial scroll is completed.. I tried the code below but its not rebinding so I'm not sure what I am doing wrong, any advice is appreciated.

        $("#wavetextcontainer").bind("mousewheel", function(event, delta) {

   //HERE IS WHERE EVENT IS UNBOUND:
     $("#wavetextcontainer").unbind("mousewheel");

        var speed = 10;
        var mySlider = $("#slider");
        var sliderVal = mySlider.slider("option", "value");

        sliderVal += (delta*speed);

        if (sliderVal > mySlider.slider("option", "max")) sliderVal = mySlider.slider("option", "max");
        else if (sliderVal < mySlider.slider("option", "min")) sliderVal = mySlider.slider("option", "min");

        $("#slider").slider("value", sliderVal);

        event.preventDefault();

      // HERE I WANT TO REBIND THE EVENT:
     $("#wavetextcontainer").bind("mousewheel");

});

Answer

Nick Craver picture Nick Craver · Jul 26, 2010

You need to store the function were you can reference it, like this:

function myHandler(event, delta) {
     $("#wavetextcontainer").unbind("mousewheel", myHandler);

        var speed = 10;
        var mySlider = $("#slider");
        var sliderVal = mySlider.slider("option", "value");

        sliderVal += (delta*speed);

        if (sliderVal > mySlider.slider("option", "max")) sliderVal = mySlider.slider("option", "max");
        else if (sliderVal < mySlider.slider("option", "min")) sliderVal = mySlider.slider("option", "min");

        $("#slider").slider("value", sliderVal);

        event.preventDefault();

      // HERE I WANT TO REBIND THE EVENT:
     $("#wavetextcontainer").bind("mousewheel", myHandler);    
};

$("#wavetextcontainer").bind("mousewheel", myHandler);

By doing this you can call .bind() later to the same function (you can't reference an anonymous one). You're currently trying to call .bind() without a function to handle anything, which doesn't work. This also has the added advantage of being able to pass that same function reference to .unbind() so it unbinds only that handler, not any mousewheel handler.


Alternatively, do this without un/re-binding, like this:

$("#wavetextcontainer").bind("mousewheel", function (event, delta) {
  event.preventDefault();
  if($.data(this, 'processing')) return; //we're processing, ignore event

  $.data(this, 'processing', true);
  var speed = 10;
  var mySlider = $("#slider");
  var sliderVal = mySlider.slider("option", "value");

  sliderVal += (delta*speed);

  if (sliderVal > mySlider.slider("option", "max")) sliderVal = mySlider.slider("option", "max");
  else if (sliderVal < mySlider.slider("option", "min")) sliderVal = mySlider.slider("option", "min");

  $("#slider").slider("value", sliderVal);
  $.data(this, 'processing', false);
});

This just uses $.data() to store a "we're working" data entry with the element, if anything hits this handler while it's true, it just returns and ignores the event.