Welcome to WebmasterWorld Guest from 50.17.114.227

Forum Moderators: open

Message Too Old, No Replies

stopping "chained" functions before they end

     
3:08 pm on Jan 20, 2013 (gmt 0)

Preferred Member

10+ Year Member

joined:Nov 10, 2005
posts:387
votes: 0


I have a jQuery slideshow in which I sometimes chain various functions together (jQuery runs in one function, ending in a call to the next function) to create a series of page effects. These extended effects can take a minute or so to run.

When the user navigates to another slide, I need to stop & reset the animation so that: a) it doesn't continue during the next slide, and b) so that if the user navigates back to the original slide, the animation starts from scratch.

Usually, some combination of stop(), clearTimeout(), or script-specific command works. Sometimes though, it doesn't. Questions:

1) Is there a way to stop animations on different elements all at once? I've tried:

.stop(true) & .stop(true, true) - doesn't always work
.clearQueue() - only works on one object
.finish() - promising, but stops my jquery slideshow too
event.stopPropagation() - stops slideshow but not animations (opposite of what I want)

I've even tried globally turning fx off, then back on:
fx.off = true; $.fx.off = false;
Also promising, but unfinished animations pick up where left off while finished ones revert to initial state.

2) Is there a better way to chain the animations together than described in my opening sentence that allows for a simple stop/reset?
10:50 pm on Jan 21, 2013 (gmt 0)

Preferred Member

10+ Year Member

joined:Nov 10, 2005
posts:387
votes: 0


I found one solution that works in some cases, but still not all:

var timer = null;

function myFunc(){
// code
timer = setTimeout("myFunc()", 1);
}

// run this on reset to stop the above function:
function stop(){
clearTimout(timer);
}

Any better ideas?
11:48 pm on Jan 21, 2013 (gmt 0)

Senior Member

WebmasterWorld Senior Member 10+ Year Member

joined:Nov 3, 2005
posts:1585
votes: 0


if .stop(true, true) is used ( 2nd true = jumpToEnd ) the callback function is called and may start a chained animation.
1:20 pm on Jan 22, 2013 (gmt 0)

Preferred Member

10+ Year Member

joined:Nov 10, 2005
posts:387
votes: 0


Yes, that's what I discovered. I only use it on statements that don't have a callback; otherwise, I use .stop(true);

I've been searching the web for this; other than my second post above, I didn't come up with much -- so maybe there's no solution. Unless somebody knows a way to set up .queue() to sequence through a series of animations working on different objects. Then I could just clear the queue.
2:40 pm on Jan 24, 2013 (gmt 0)

Preferred Member

10+ Year Member

joined:Nov 10, 2005
posts: 387
votes: 0


I guess there's no clear answer to this, so I'll continue to minimize it as best I can using the above methods.

I've got email notification on for this topic and welcome further reply; otherwise, I'll consider it closed.
10:06 pm on Jan 28, 2013 (gmt 0)

Preferred Member

10+ Year Member

joined:Nov 10, 2005
posts: 387
votes: 0


Update - for anyone looking for a solution to this, I found the following:

First, the culprit: jQuery .delay() does not respond to .stop(); from the jQuery docs:

The .delay() method is best for delaying between queued jQuery effects. Because it is limited it doesn't, for example, offer a way to cancel the delay .delay() is not a replacement for JavaScript's native setTimeout function, which may be more appropriate for certain use cases.

I'm not the only one who's brought this up; the following bug tickets suggest fixes, but I couldn't get them to work (I include them in case better skilled coders can figure them out):

[bugs.jquery.com...] - implies that the 'bug' was fixed as of jquery 1.7, but I upgraded to the latest version and still had the problem

[bugs.jquery.com...] - suggests clearQueue(), but as another poster pointed out here ( [bugs.jquery.com...] ), it doesn't always work

*********

SOLUTIONS: I found two plug-ins that do the trick:

.doTimeout() [benalman.com...] works so far for me

.delayed() [theloveofcode.com...] - this one is chainable and has more functionality; the problem though is that it only works on specific events (i.e. click, onload, etc.); I need it to work directly from a selector: $("id").delay(5000).animate(...);

If anyone can get it to work that way, I'd like to know.
12:23 am on Jan 29, 2013 (gmt 0)

Senior Member

WebmasterWorld Senior Member 10+ Year Member

joined:Nov 3, 2005
posts:1585
votes: 0


Good find

.animate() would also be worth a try, animating nothing ( or nothing visible )
1:33 pm on Jan 29, 2013 (gmt 0)

Preferred Member

10+ Year Member

joined:Nov 10, 2005
posts: 387
votes: 0


Yes - I saw that hack posted by someone in the jquery forum. I couldn't get it to work animating nothing, so I think you have to include a dummy CSS call that doesn't really change anything (like "z-index": 1, or opacity: 1 for already visible elements). You also have to include a time to sub for the delay. So:

$("id").animate({"z-index": 1}, 5000).animate(...);

is the same as:

$("id").delay(5000).animate(...);

except that you can stop it with:

$("id").stop(true);
2:08 pm on Jan 29, 2013 (gmt 0)

Preferred Member

10+ Year Member

joined:Nov 10, 2005
posts: 387
votes: 0


BTW, minor correction: the doTimeout() plug-in mentioned above is chainable too.
9:47 pm on Jan 29, 2013 (gmt 0)

Senior Member

WebmasterWorld Senior Member 10+ Year Member

joined:Nov 3, 2005
posts:1585
votes: 0


Or invent your own property seems to be OK

$("id").animate({x:1}, 5000).animate(...);
3:53 pm on July 24, 2013 (gmt 0)

Preferred Member

10+ Year Member

joined:Nov 10, 2005
posts:387
votes: 0


For anyone still following this topic (or who lands here via search), below is an update and a decent solution.

First, some clarification about jQuery stop() -- most here probably know this, but if not it'll confuse you as it did me. I thought stop() applies to the entire chained command; it does not. It applies to the SPECIFIC animation in the chain running at the moment stop() is called.

So in the chain:

$("#ID").fadeIn(1000).delay(1000).fadeOut(1000, do_next_func);

stop() acts on either of the three items attached to the object "#ID". That completely changes how it acts with and without the various 'true' flags. Each apply only to the specific animation being run, not the chain. (Example: stop(true,true) does NOT execute do_next_func() if called during fadeIn(1000), but stop() DOES.)

This may have resulted in my misunderstanding my own tests on this, because I now find that stop() DOES work on delay(). My earlier post was incorrect.

Last, I hit on a simple solution for stopping a line of animations tied together by successive function calls. Example:

function do_1() { $("#ID1").fadeIn(1000, do_2); }
function do_2() { $("#ID2").fadeIn(1000, do_3); }
function do_3() { $("#ID3").fadeIn(1000); }

If you have a long list of animations on various #IDs, it's a hassle managing the stop()'s. But it's easy if you add a single class to each object (e.g. <div class="ID" id="ID1"></div>, <div class="ID" id="ID2"></div>, etc). Then you can stop everything with a single command: $(".ID").stop()
6:03 pm on July 24, 2013 (gmt 0)

Preferred Member

10+ Year Member

joined:Nov 10, 2005
posts:387
votes: 0


Also found a few more methods:

$('[id]').stop(true); // stops any element with an id
$('[id^="ID"]').stop(true); // stops any element with id that starts with "ID"
$(".ID [id]").stop(true); // stops any element that's a descendant of class="ID" and has an id

Other similar commands work as well.

Question: which uses more resources, stopping via a class selector that applies to say, 10 elements, or via $('[id]'), where 10 elements have id's?
8:13 pm on July 25, 2013 (gmt 0)

Moderator from CA 

WebmasterWorld Administrator httpwebwitch is a WebmasterWorld Top Contributor of All Time 10+ Year Member

joined:Aug 29, 2003
posts:4059
votes: 0


id selection is almost always faster, but you could test that to know for certain
1:36 pm on July 26, 2013 (gmt 0)

Preferred Member

10+ Year Member

joined:Nov 10, 2005
posts:387
votes: 0


yes, I tested and that seems to be true, with one caveat: limit the number of ID's beings checked as much as possible. General ID checks, if your page has many (besides the ones you want to stop), are slowest:

$('[id]').stop(true);

The fastest one I found was:
$('[id^="testID"]').stop(true);
which zeroes in on ID's w/specific name strings

Next best is:
$(".ID").stop(true);
assuming class "ID" is only assigned to the animations you want to stop.

That method works just as fast as the fastest one if you tweak it like so:
$(".ID [id]").stop(true);
(not sure why, since in my test it didn't reduce the number of elements checked; maybe just because it's more specific -- doesn't have to LOOK for more)