Reputation: 21890
I've got a page of divs which I want to reorder on page load, moving divs of a specific class to the top of the page.
For the most part I have this working using insertAfter()
. However, I'd like to fire the events in sequence so there's more of a stair-step to the animation.
You can see where I'm at currently with this jsFiddle.
HTML:
<div class="lists">
<div class="marker"></div>
<div class="row0">Item</div>
<div class="row0">Item</div>
<div class="row0">Item</div>
<div class="row99">Item</div>
<div class="row0">Item</div>
<div class="row0">Item</div>
<div class="row0">Item</div>
<div class="row99">Item</div>
<div class="row0">Item</div>
<div class="row99">Item</div>
<div class="row0">Item</div>
</div>
Using this jquery it functions.
$('.row99').each(function(i,e){
$(e).delay(500).slideUp(1000, function(){
$(this).insertAfter('.marker').slideDown(1000);
});
});
As you'll see, on page load specific divs are slid up, inserted at the top, then slid down. However, all the special divs fire at the same time.
Is there a way to make these items fire one after another rather than all at the same time?
Secondary is you'll see that when the divs slide down, then are in reverse order (10-8-4). This isn't a big deal, but if there's a way to retain the basic order (4-8-10) rather than reversing it, I'd love that as well.
Upvotes: 1
Views: 237
Reputation: 179176
Rather than rely on specific timings, I recommend using queueing via jQuery's .queue()
method:
$('.row99').each(function(i,e){
$('.lists').queue(function (n) {
$(e).slideUp(1000)
.queue(function (next) {
$(this).insertAfter('.marker');
next();
}).slideDown(1000, n);
});
});
The way this works is that each animation is queued in order on a shared object. In this example, I queued everything on the .lists
element.
The n
and next
parameters are the .dequeue()
callbacks that tell the queue to move on to the next item in the queue.
Within $('.lists').queue(...
you can see that I chose to use another queue
call rather than passing a complete
callback to slideUp
. This is because the callback parameters cause "Arrow Code" especially when there are callbacks within callbacks.
The advantage to coding this way is that there is no reliance on the duration of the animations. You can feel free to change the durations in a single location and the queueing behavior will continue to work as expected.
There are many ways of fixing the ordering issue. A simple one is to add a class to the moved elements and position all subsequent elements after the last moved element (same thing outlined by adeneo):
fiddle:$('.row99').each(function(i,e){
$('.lists').queue(function (n) {
$(e).slideUp(1000)
.queue(function (n) {
$(this).insertAfter($('.marker, .moved').last()).addClass('moved');
n();
}).slideDown(1000, n);
});
});
Upvotes: 1
Reputation: 707786
Here's a way to use completion functions to make them run one after the other without really changing your main logic much at all:
(function() {
var items = $(".row99");
var index = 0;
function next() {
if (index < items.length) {
items.eq(index++).slideUp(1000, function() {
$(this).insertAfter('.marker').slideDown(1000, next);
});
}
}
next();
})();
Working demo: http://jsfiddle.net/jfriend00/ZfVw5/
In a nutshell, you use exactly the same code you were using, but instead of running the operation in a .each()
loop, you run one at a time advancing a counter each time so you can fetch the next one in the list. The completion function from the ending .slideDown()
starts the next iteration. The whole thing finishes when your counter points past the end of your list of objects.
Upvotes: 2
Reputation: 318302
Just stack the delays
$('.row99').each(function(i,e){
$(e).delay((i+1)*1000).slideUp(1000, function(){
$(this).insertAfter('.marker').slideDown(1000);
});
});
A simple way to keep the order would be to add a class, get the last instance of that class, and insertAfter that instead
$('.row99').each(function (i, e) {
$(e).delay((i + 1) * 1000).slideUp(1000, function () {
var n = i!==0 ? $('.moved:last') : $('.marker');
$(this).insertAfter(n).addClass('moved').slideDown(1000);
});
});
Upvotes: 2