noelietrex
noelietrex

Reputation: 67

JQuery .each() loop continue looping

I have a jQuery .each() loop that I want to continue looping. In my current fiddle it loops, starting over and everything, but I can't seem to get the timing right for various numbers of li's. I want this loop to work no matter how many or few list items there are.

https://jsfiddle.net/ewsQ7/1662/

// add class first to first li
$('.js-ifeature li').first().addClass('message-first js-selected');

// add class last to last li
$('.js-ifeature li').last().addClass('message-last');

//set height
$('.js-ifeature').css('height', $('.js-ifeature li').height()+'px');

var time = 1000;
var alltheitems = $('.js-ifeature li').size();

function eachChange(){
    $('.js-ifeature li').each(function(i) {
        $(this).hide();
        $(this).delay(time * i).fadeIn(time).fadeOut(time);
        if ($(this).hasClass('message-last')) {
            setTimeout(eachChange, (alltheitems) * time);
        }
    });
}
eachChange();

Upvotes: 4

Views: 236

Answers (2)

nnnnnn
nnnnnn

Reputation: 150020

The .each() loop is a little unwieldy for this sort of timing between multiple elements. Even if it worked now it would break if you decided to add extra steps into the individual animations. I'd get rid of it and do something like this instead:

var time = 1000,
    current = 0,
    $lis = $('.js-ifeature li').hide(); // hide them all to start

$lis.first().addClass('message-first js-selected'); // add class first to first li
$lis.last().addClass('message-last'); // add class last to last li
$('.js-ifeature').css('height', $lis.height()+'px');

function eachChange(){
    $lis.eq(current).fadeIn(time).fadeOut(time, eachChange);
    current = (current + 1) % $lis.length;
}
eachChange();

Demo: https://jsfiddle.net/ewsQ7/1664/

That is, have your function animate only the "current" element, tracked via the current variable, and use the fact that .fadeOut() lets you specify a callback that jQuery will call when the fade is complete to trigger the next element's animation. (Note that you probably don't need the message-last class anymore but I've left that code in.)

Upvotes: 1

Ryan Wheale
Ryan Wheale

Reputation: 28390

This is a handy situation for the not-so-commonly-used shift method. But since jQuery collections are not arrays but rather array-like objects, you have to shim the shift method onto jQuery:

Also, you should wait until the fadeOut is completely done before doing the next call as the browser might get choked up and you would eventually end up with a stack up of animations... which is not good.

http://jsfiddle.net/xwuo9cpy/2/

var $featue = $('.js-ifeature'),
    $items = $featue.find('li'),
    time = 1000;

//set height
$featue.css('height', $items.first().height()+'px');
$items.hide();

// shim the shift method
$.fn.shift = Array.prototype.shift;

!function eachChange(){
    var item = $items.shift();
    $(item).fadeIn(time).fadeOut(time, eachChange);
    $items.push(item);
}();

Upvotes: 1

Related Questions