jremydeaton
jremydeaton

Reputation: 133

How to kill a looping function in jquery

I created a function that iterates over a set of divs, looping, fading in and out the next one.

What I am trying to do is to stop it upon either 'click', if/else, or focus. In doing some searching, it seems that I can utilize the setTimeout - clearTimeout functions. However I am a bit unclear on how to go about it, and maybe implementing it incorrectly.

Fiddle Me This Batman

HTML:

<a href="#" class="killFunc">Kill Loop Function</a>
<div id="productBox">
    <h3>Dynamic Title Here</h3>

    <div class="divProduct">
        <!-- product image -->
        <div class="product-discription">
            <h4>Product 1</h4>
            <p>Cras justo odio, dapibus ac facilisis in.</p>
            <a href="#">Learn More</a>
        </div>
    </div>

    <!-- Repeat '.divProduct' over and over -->

</div>

JS:

timer = null;

function productTypeCycle(element) {

    timer = setTimeout(function() {

        element.fadeIn()
               .delay(1000)
               .fadeOut(function() {
                   if(element.next().length > 0) {
                       productTypeCycle(element.next());
                   }
                   else {
                       productTypeCycle(element.siblings(":nth-child(2)"));
                   }
              });
   }, 500);
}

$(document).ready(function() {
    productTypeCycle($(".divProduct:first"));
    $(".killFunc").click(function(e) {
        e.preventDefault();
        if(timer !== null) {
            clearTimeout(timer);
        }
    });
});

Of course, as usual, I am probably way over thinking something that could be so simple.

Upvotes: 0

Views: 905

Answers (3)

luk2302
luk2302

Reputation: 57204

the problem here is that you stop your timer correctly, but sadly your timer has internally via jQuery started another "timer" for the animations. you would need to stop the animation instead of the timer:

var animationEle = null;
function productTypeCycle(element) {
  animationEle = element;
  element.fadeIn()
    .delay(1000)
    .fadeOut(function () {
    if (element.next().length > 0) {
      productTypeCycle(element.next());
    } else {
      productTypeCycle(element.siblings(":nth-child(2)"));
    }
  });
}

$(document).ready(function () {
  productTypeCycle($(".divProduct:first"));
  $(".killFunc").click(function (e) {
    e.preventDefault();
    if (animationEle)
      $(animationEle).stop(true, false);
  });
});

working fiddle

Upvotes: 1

Smeegs
Smeegs

Reputation: 9224

Another (cleaner) way to go about it, is to let the last animation finish, but set a value to stop any further animations.

http://jsfiddle.net/hhwfq/54/

Like this.

timer = null;
var animationCancelled = false;
function productTypeCycle(element) {

    timer = setTimeout(function() {        
        element.fadeIn()
               .delay(1000)
               .fadeOut(function() {
                   if(animationCancelled) return;
                   if(element.next().length > 0 ) {
                       productTypeCycle(element.next());
                   }
                   else {
                       productTypeCycle(element.siblings(":nth-child(2)"));
                   }
              });
   }, 500);
}

$(document).ready(function() {
    productTypeCycle($(".divProduct:first"));
    $(".killFunc").click(function(e) {
        e.preventDefault();
        if(timer !== null) {
            clearTimeout(timer);            
            animationCancelled = true;
        }
    });
});

Upvotes: 1

Smeegs
Smeegs

Reputation: 9224

The issue is the fade, not the timer. The fade is still executing. You need to run $(element).stop(); on all the elements that have started an animation otherwise they'll just continue.

Upvotes: 0

Related Questions