homepage Welcome to WebmasterWorld Guest from 54.145.252.85
register, free tools, login, search, pro membership, help, library, announcements, recent posts, open posts,
Become a Pro Member
Home / Forums Index / Code, Content, and Presentation / JavaScript and AJAX
Forum Library, Charter, Moderator: open

JavaScript and AJAX Forum

    
stopping "chained" functions before they end
sssweb

5+ Year Member



 
Msg#: 4537712 posted 3:08 pm on Jan 20, 2013 (gmt 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?

 

sssweb

5+ Year Member



 
Msg#: 4537712 posted 10:50 pm on Jan 21, 2013 (gmt 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?

daveVk

WebmasterWorld Senior Member 5+ Year Member



 
Msg#: 4537712 posted 11:48 pm on Jan 21, 2013 (gmt 0)

if .stop(true, true) is used ( 2nd true = jumpToEnd ) the callback function is called and may start a chained animation.

sssweb

5+ Year Member



 
Msg#: 4537712 posted 1:20 pm on Jan 22, 2013 (gmt 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.

sssweb

5+ Year Member



 
Msg#: 4537712 posted 2:40 pm on Jan 24, 2013 (gmt 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.

sssweb

5+ Year Member



 
Msg#: 4537712 posted 10:06 pm on Jan 28, 2013 (gmt 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.

daveVk

WebmasterWorld Senior Member 5+ Year Member



 
Msg#: 4537712 posted 12:23 am on Jan 29, 2013 (gmt 0)

Good find

.animate() would also be worth a try, animating nothing ( or nothing visible )

sssweb

5+ Year Member



 
Msg#: 4537712 posted 1:33 pm on Jan 29, 2013 (gmt 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);

sssweb

5+ Year Member



 
Msg#: 4537712 posted 2:08 pm on Jan 29, 2013 (gmt 0)

BTW, minor correction: the doTimeout() plug-in mentioned above is chainable too.

daveVk

WebmasterWorld Senior Member 5+ Year Member



 
Msg#: 4537712 posted 9:47 pm on Jan 29, 2013 (gmt 0)

Or invent your own property seems to be OK

$("id").animate({x:1}, 5000).animate(...);

sssweb

5+ Year Member



 
Msg#: 4537712 posted 3:53 pm on Jul 24, 2013 (gmt 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()

sssweb

5+ Year Member



 
Msg#: 4537712 posted 6:03 pm on Jul 24, 2013 (gmt 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?

httpwebwitch

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



 
Msg#: 4537712 posted 8:13 pm on Jul 25, 2013 (gmt 0)

id selection is almost always faster, but you could test that to know for certain

sssweb

5+ Year Member



 
Msg#: 4537712 posted 1:36 pm on Jul 26, 2013 (gmt 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)

Global Options:
 top home search open messages active posts  
 

Home / Forums Index / Code, Content, and Presentation / JavaScript and AJAX
rss feed

All trademarks and copyrights held by respective owners. Member comments are owned by the poster.
Home ¦ Free Tools ¦ Terms of Service ¦ Privacy Policy ¦ Report Problem ¦ About ¦ Library ¦ Newsletter
WebmasterWorld is a Developer Shed Community owned by Jim Boykin.
© Webmaster World 1996-2014 all rights reserved