Loop through sequential animations using $.each and setInterval? - javascript

I have a set of divs:
<div class="alert-container">
<div class="alert">alert 1 text</div>
<div class="alert">alert 2 text</div>
<div class="alert">alert 3 text</div>
</div>
I want to animate them one-by-one as follows:
alert 1 slideInDown > wait 3s > alert 1 slideOutDown >
alert 2 slideInDown > wait 3s > alert 2 slideOutDown >
alert 3 slideInDown > wait 3s > alert 3 slideOutDown >
repeat from [1]
The current state of my JS is as this:
$('.alert-container .alert').each(function(index) {
$(this).addClass('animated slideInDown').show().one(animationEnd, function(){
$(this).removeClass('animated slideInDown').addClass('animated slideOutDown').one(animationEnd, function(){
$(this).removeClass('animated slideOutDown').hide();
});
});
});
I'm using animate.css, as can be seen by the classes being added, and this currently has the result of simultaneously animating all three .alert divs, which is what I expect. Now I just need to modify this to animate one-by-one, and repeat infinitely.
Even after reviewing other SO posts, I'm struggling to wrap my head around where to use setInterval and $.each in order to achieve the results I want, and whether I should be using an initialDelay variable based on index etc.
Please help. Many thanks.

You may try below code:
$(document).ready(function(){
var slideArray = $(".alert-container > .alert");
var slideTime = 3000; //3 seconds
var currentSlideIndex = 0;
setInterval(function(){
if(currentSlideIndex < slideArray.length){
animateSlide(currentSlideIndex);
currentSlideIndex++;
}
else
{
currentSlideIndex = 0;
animateSlide(currentSlideIndex);
}
},slideTime);
function animateSlide(slideIndex){
var slideObject = slideArray[slideIndex]; //get the slide object to animate
$(slideObject).addClass('animated slideInDown').show().one(animationEnd, function(){
$(slideObject).removeClass('animated slideInDown').addClass('animated slideOutDown').one(animationEnd, function(){
$(slideObject).removeClass('animated slideOutDown').hide();
});
});
}
})
Basically you can't directly use setInterval in $.each loop. So to avoid that approach you can animate one slide at a time by its index.
Note - I couldn't able to test above code. But I guess it should work.

If anyone wants to see the exact code implemented using vijayP's answer, here it is:
jQuery(document).ready(function($) {
var alertArr = $(".alert-container .alert");
var alertTime = 6500;
var visibleAlert = 0;
var animationEnd = 'webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend';
// loop through array of alerts
function loopAlerts(){
if(visibleAlert < alertArr.length ) {
animateAlert(visibleAlert);
visibleAlert++
} else {
visibleAlert = 0;
animateAlert(visibleAlert);
visibleAlert++
}
}
// alert slideInDown > wait 3s > slideOutDown
function animateAlert(visibleAlert){
var alert = alertArr[visibleAlert];
$(alert).addClass('slideInDown').removeClass('hide').one(animationEnd, function(){
$('.minor-alerts .marquee .alert').removeClass('slideInDown slideOutDown');
setTimeout(function(){
$(alert).addClass('slideOutDown').one(animationEnd, function(){
$(alert).addClass('hide').removeClass('slideOutDown slideInDown');
});
}, 3000);
});
}
setInterval(loopAlerts, alertTime);
});

Related

Refresh a DIV content after faded it out

I got X DIV (TopRowRight1, TopRowRight2, TopRowRight3...) , each containing a different Google Geochart generated by a php page : GeochartPerProvince.php?template=X.
function getResult(template){
jQuery.post("GeochartPerProvince.php?template="+template,function( data ) {
jQuery("#TopRowRight"+template).html(data);
});
}
jQuery().ready(function(){
getResult(1);
setInterval("getResult(1)",10000);
getResult(2);
setInterval("getResult(2)",10000);
getResult(3);
setInterval("getResult(3)",10000);
});
jQuery(function () {
var $els = $('div[id^=TopRowRight]'),
i = 0,
len = $els.length;
$els.slice(1).hide();
setInterval(function () {
$els.eq(i).fadeOut(function () {
i = (i + 1) % len
$els.eq(i).fadeIn();
})
}, 5000)
});
Every 5 seconds, i fade out one and fade in the next one. This works perfectly.
For now, the php page in the DIV is refreshed every 10 seconds. This works too.
But what i dream about is that the php page in the DIV is reloaded AFTER the DIV is faded out instead of every 10 seconds. How to do it?
Solved. How it works properly:
function getResult(template){
jQuery.post("GeochartPerProvince.php?template="+template,function( data ) {
jQuery("#TopRowRight"+template).html(data);
});
}
$(document).ready(function(){
getResult(0);
getResult(1);
getResult(2);
//setInterval("getResult(2)",10000); <== keep this piece of code in case of need.
});
$(document).ready(function () {
var $els = $('div[id^=TopRowRight]'),
i = 0,
len = $els.length;
$els.slice(1).hide();
setInterval(function () {
$els.eq(i).fadeOut(function () {
i = (i + 1) % len
getResult(i);
$els.eq(i).fadeIn();
})
}, 10000)
});
You're already using a callback function after the element has been faded out. So why not call your getResult function inside it?
$el.fadeOut(function(){
// stuff
getResult(i)
})
I have a few suggestions and an example code for you to achieve what you need :
Use $ instead of jQuery for easier reading / writing
$(document).ready is the proper start point for dom related functions
If only one div is visible at a time, do not use too many divs. Most of the time one div is enough for alternating / refreshing content. If there is in/out animation or cross-fading, two divs would be needed. (Example below uses two divs)
Avoid using setInterval except you really really need. Logics with setTimeout better handles unexpected delays such $.post may cause.
start with html code something like this:
...
<div class="top-row-right" style="display:block"></div>
<div class="top-row-right" style="display:none"></div>
...
js:
$(document).ready( function() {
var len = 4; // 'I got X DIV..' This is where we put the value of X.
var template = -1;
function refreshChart() {
template = (template + 1) % len;
$.post("GeochartPerProvince.php?template="+template, function(data) {
var offscreenDiv = ('.top-row-right:hidden');
var onscreenDiv = ('.top-row-right:visible');
offScreenDiv.html(data);
onScreenDiv.fadeOut('slow', function() {
offScreenDiv.fadeIn();
setTimeout(refreshChart, 10000);
});
});
}
refreshChart();
});

Multiple instances of Setinterval

I have a little problem with my code.
I have it setup so that by default, a rotating fadeIn fadeOut slider is auto playing, and when a user clicks on a li, it will jump to that 'slide' and pause the slider for x amount of time.
The problem i have is that if the user clicks on multiple li's very fast, then it will run color1() multiple times with will start colorInterval multiple times. This gives a undesired effect.
So what i need help with, is figuring out how to reset my code each time a li is clicked, so whenever ColorClick is clicked, i want to make sure that there are no other instances of colorInterval before i start a new one.
Thanks in advance!
=================================
edit:
I now have another problem, i believe that i fixed the clearInterval problem, but now if you look at var reset, you'll see that it runs color1() each time a li is clicked, which runs multiple intervals, so i need to delete the previous instance of color1() each time it is called, to make sure that it doesnt repeat any code inside multiple times. So when a li is clicked delete any instances of color1()
or
i need that instead of running color1 in var reset, i will go straight to colorInterval instead of running color1() for each li clicked,
so run colorInterval after x amount of time in var reset.
function color1() {
var pass = 0;
var counter = 2;
var animationSpeed = 500;
var $colorContent = '.color-container-1 .color-content-container'
var $li = '.color-container-1 .main-color-container li'
$($li).on('click', function() {
colorClick($(this));
});
function colorClick($this) {
var $getClass = $this.attr("class").split(' ');
var $whichNumber = $getClass[0].substr(-1);
var $Parent = '.color-container-1 ';
pass = 1;
$($colorContent).fadeOut(0);
$($colorContent + '-' + $whichNumber).fadeIn(animationSpeed);
var reset = setTimeout(function() {
clearTimeout(reset);
pass = 0;
color1();
}, 10000);
}
var colorInterval = setInterval(function() {
if (pass > 0) {
clearInterval(colorInterval);
return; //stop here so that it doesn't continue to execute below code
}
$($colorContent).fadeOut(0);
$(($colorContent + '-' + counter)).fadeIn(animationSpeed);
++counter
if (counter === $($colorContent).length + 1) {
counter = 1;
}
}, 7000);
}
You could just clear the interval inside of the click event.
var colorInterval;
$($li).on('click', function() {
clearInterval(colorInterval);
colorClick($(this));
});
//Your other code
colorInterval = setInterval(function() {
//Rest of your code
});
One thing play with is jQuery animations have a pseudo class selector :animated when animation is in progress
if(!$('.your-slide-class:animated').length){
// do next animation
}

setTimeout not working, other methods of queuing in a for loop?

Code below (the divs are shaded in my real example, I want to sequentially decrease their opacity to 0 so each disappears, in order.
I tried to doing this without using setTimeout, but all of the divs disappeared simultaneously - its good to know that the part of the code that changes the opacity works, but I cant seem to get them to work sequentially.
When I try to use setTimeout (which I presume I am implementing incorrectly),nothing happens!
Any help would be really appreciated with this, I'm fairly new to JavaScript and haven't touched it in a while and tutorials haven't been able to help me.
<body>
<div id="div1"></div>
<div id="div2"></div>
<div id="div3"></div>
<div id="div4"></div>
<script type="text/javascript">
// the divs that we want to cycle through are named here.
var divs = ["#div1", "#div2", "#div3", "#div4"];
var divsLength = divs.length;
for (var i = 0; i < divsLength; i++) {
setTimeout(function(){
$(divs[i]).fadeTo(1000, 0, function() {
});
},1500);
};
</script>
</body>
Here's a way you should be able to do this without setTimeout:
function doFade(items, index) {
$(items[index]).fadeTo(1000, 0, function() {
doFade(items, index + 1);
});
}
doFade(divs, 0);
If you're targetting browsers that support ES5 (most modern versions do), then you can further simplify doFade:
function doFade(items, index) {
$(items[index]).fadeTo(1000, 0, doFade.bind(this, items, index + 1));
}
working jsfiddle
You can use a recursive function to do that kind of thing, something like that :
function seqFade($el){
$el.first().fadeOut(500, function(){ //Take the first element and fade it out
seqFade($el.slice(1)); //Recall the function when complete with the same set of element minus the first one.
})
}
seqFade($('div')); //Call the function
http://jsfiddle.net/L2fvdfy2/
In your code, it could look like that :
function seqFade($el){
$el.first().fadeOut(500, function(){
seqFade($el.slice(1));
})
}
seqFade($('#div1, #div2, #div3, #div4'));
It's because when the timeout finally fires the variable "i" only has the last index value. Also the loop will start all the timeouts at almost the same time.
There are other ways to accomplish it but this might work with minimal changes to your code.
Try this:
<script type="text/javascript">
var divs = ["#div1", "#div2", "#div3", "#div4"];
var divsLength = divs.length;
for (var i = 0; i < divsLength; i++) {
setTimeout((function(index) {
return function(){
$(divs[index]).fadeTo(1000, 0, function() { });
}
)(i)),1500 + (i * 1500));
};
</script>
</body>
This will create an instance of the function with it's own copy of the index when it was called. Also increasing the timeout of each timeout will have them execute sequentially.
try this:
// the divs that we want to cycle through are named here.
var divs = ["#div1", "#div2", "#div3", "#div4"];
(function fade(i) {
$(divs[i]).fadeTo(1000, 0, function() {
setTimeout(function() {fade(++i);}, 500);
});
})(0);
for (var i = 1; i <= divsLength; i++) {
setTimeout(function(){
$(divs[i]).fadeTo(1000, 0, function() {
});
},1000*i);
lets try this

create simple rotation with pause

How can I cycle through a series of elements, adding a class, pausing then removing the class and moving on to the next element. I have tried setInterval and I have tried setTimeout, but cannot seem to get it to work.
My Javascript
var numpromos = $('.promoteBlock').length;
var promonum = 1;
while (numpromos > promonum){
setInterval(function() {
$('#promoteCont .promoteBlock').fadeOut().removeClass('active');
$('#promoteCont #promo'+promonum).addClass('active');
}
}, 3000);
promonum++;
}
My HTML
<div id="promoteCont">
<div id="promo1" class="promoteBlock">Promotion No.1</div>
<div id="promo2" class="promoteBlock">Second Promo</div>
<div id="promo3" class="promoteBlock">Another one</div>
</div>
function playNext(){
console.log("playNext");
var active = $('#promoteCont').find(".promoteBlock.active");
if( active.length == 0 )
active = $(".promoteBlock:eq(0)");
var fout = active.next();
if( fout.length == 0 )
fout = $(".promoteBlock:eq(0)");
active.fadeOut().removeClass('active');
fout.fadeIn().addClass('active');
setTimeout(function(){
playNext();
},3000);
}
setTimeout(function(){
playNext();
},3000);
http://jsfiddle.net/p1c3kzj7/
Take things out of the while loop. You only need to set the interval once. Perform your state calculation (which item is selected) within the callback method itself. See below, which I believe is what your looking for.
// Global variables to maintain state... I'm sure I'll get some comments about these :p
var numpromos = $('.promoteBlock').length;
var promonum = 1;
$document.ready(function()
{
setInterval(function() {
$('#promoteCont .promoteBlock').fadeOut().removeClass('active');
$('#promoteCont #promo'+promonum).addClass('active');
promonum++;
if(promonums > numpromos)
promonum = 1;
}, 3000);
});

Help with JQuery Callback

As per my previous question, I have a working animation which fades in and out each element within the div slideshow. The problem is that I want this animation to continue from the beginning once it has reached the last element. I figured that was easy and that I'd just place an infinite loop inside my JQuery function, but for some reason if I insert an infinite loop, no animation displays and the page hangs. I also cannot find anything in the documentation about how properly place a callback. How can I get this code to restart from the beginning of the animation once it finishes iterating over each object and why is an infinite loop not the right way to go about this?
<div id="slideshow">
<p>Text1</p>
<p>Text2</p>
<p>Test3</p>
<p>Text4</p>
</div>
<script>
$(document).ready(function() {
var delay = 0;
$('#slideshow p').each(
function (index, item)
{
$(this).delay(delay).fadeIn('slow').delay(800).fadeOut('slow');
delay += 2200;
}
);
});
</script>
You could do something like this:
$(function() {
var d = 2200;
function loopMe() {
var c = $('#slideshow p').each(function (i) {
$(this).delay(d*i).fadeIn('slow').delay(800).fadeOut('slow');
}).length;
setTimeout(loopMe, c * d);
}
loopMe();
});
You can give it a try here.
Instead of keeping up with a delay, you can just multiple it by the current index in the loop...since the first index is 0, the first one won't be delayed at all, then 2200ms times the amount of elements later, do the loop again. In the above code d is the delay, so it's easily adjustable, and c is the count of elements.
This solution is in my opinion more elegant, also more natural, it is easier to control, to correctly edit values of delays etc. I hope you'll like it.
$(document).ready(function () {
var elementsList = $('#slideshow p');
function animationFactory(i) {
var element = $(elementsList[i % elementsList.length]);
return function () {
element.delay(200).fadeIn('slow').delay(800).fadeOut('slow', animationFactory(i + 1));
};
}
animationFactory(0)();
});

Categories

Resources