Dan Dan - 5 months ago 26
jQuery Question

JavaScript function loops automatically

I have two functions to clearly explain what I mean.

Function 1
In this function if you hover over the square it will start the transition for toggling the class. However if you move the mouse off the element and then back on whilst the function is still going it will wait till the function is finished then it will repeat the function automatically. Whilst this repeat is happening the object is non intractable. For example, whilst it is repeating if you were to hover over it, it will not stay out, it will wait till the function is over and then repeat one more time because you hovered over it. Then it will allow you to hover over the element and interact with it.

$(function () {
$('square').hover(function () {
$(this).addClass("makebig", 1000, "easeInBack");
}, function(){
$(this).removeClass("makebig", 1000, "easeInBack");
});
});


Function 2
In this function when you click on the square it will begin the transition of either adding or removing the class however if you were to click on the square before the transition had ended then the function will wait for the transition to end then it will automatically start to toggle the class again. If you were to click on it five times in a row then it would toggle the class 5 times in a row one after the other.

$("square").click(function() {
$(this).toggleClass("big-blue", 1000, "easeOutSine");
});


The Question
Is there a way to make these functions interruptible?

So for
Function 1
if you were to stop hovering over the element half way through the transition it would start to automatically remove the class or if you were to hover over it whilst the transition for removing the class was going on then it would start to add the class again before the removing class transition finished. And for
Function 2
if you were to click on the element half way through the transition of toggling the class then it would begin to toggle the class again instead of completing the original transition.

Edit
As mentioned in the comments below by A. Wolff there is a
jQuery
function called
stop
however as you can see in thie JSFiddle it is not very effective as
stop(true)
does not work and
stop(true, true)
/
stop(true, true, false)
almost work however they both jump to the end of the animation and they are both glitchy.

Any way to fix this or improve the effectiveness of
stop()
would be appreciated

Answer

The trick here is to check 2 things:

  1. If the element is still being animated while another event triggers
    this is a very common practice when using jquery animations that trigger from events
  2. If the element is still being hovered (or is not hovered anymore) at the end of the animation, if it's not, set it to the right state
    This is a special case for hovering animations or other animations that might get stuck into a wrong state due to the "is still being animated" check

If you don't check these 2 things jquery will keep queuing animations while you hover in and out of the element

This should work: https://jsfiddle.net/sf5q4jv0/10/

I have made the "click" animation to stop when another one is started while the "hover" animation to complete before being able to queue a new one, but keeping in mind the 2 rules above it should be easy to animate the items as you please

$(function () {
     $('a[href*="#"]').click(function () {
         if($('html,body').data("anim")){
             $('html,body').stop();
         }
         $('html,body').data("anim", true);
         var $target = $(this.hash);
         $target = $target.length ? $target : $('html');
         var targetOffset = $target.offset().top;
         $('html,body').animate({scrollTop: targetOffset}, {duration: 1500, easing: 'easeInOutCubic'}, 
         function(){
             $('html,body').data("anim", false);
         });
         return false;
     });
});

/*Important Part*/
$(function () {
function hoverIn(element) {
  if(!$(element).data("anim")) {
    $(element).data("anim", true);
        $(element).addClass("hover", 1000, "easeOutBounce", function(){
        $(element).data("anim", false);
      //if it's not hovered anymore it will remove the class
      if(!$(element).is(":hover")) {
        hoverOut(element);
      }
    });
    }
}

function hoverOut(element) {
  if(!$(element).data("anim")) {
    $(element).data("anim", true);
        $(element).removeClass("hover", 1000, "easeOutBounce", function(){
        $(element).data("anim", false);
      //if it's not hovered anymore it will remove the class
      if($(element).is(":hover")) {
        hoverIn(element);
      }
    });
    }
}
    $('nav').hover(function(){hoverIn(this); }, function() {hoverOut(this); });
});
Comments