how can I execute a function in a loop in a way that the next element in the loop is only executed when the previous element has been done.
$(".welcome>p").each(function() {
var $this = $(this);
setTimeout(function() {
$this.animate({
opacity: 1
}, 600);
});
});
So, all the p element in this code will be running at the same time. How can I change it so that the p element will show up one by one by its order?
Thanks,
YonL
The first argument of each is index, so you could use that index to increment the setTimeout like:
$(".welcome>p").each(function( idx ) {
var $this = $(this);
setTimeout(function() {
$this.animate({
opacity: 1
}, 600);
}, idx * 600);
});
Related
I build this scraping out the answers on stackoverflow. What i want to achive:
For each .element in .element-wrapper add the class .visible with delay 1000ms .
$('.element-wrapper').children('.element').each(function(i) {
var $item = $(this);
setTimeout(function() {
$('.element').addClass('visible');
}, 1000 * i);
});
Actually you are almost right... Just change one line below to make it context sensitive to the current wrapper:
$('.element-wrapper').children('.element').each(function(i) {
var $item = $(this);
setTimeout(function() {
$item.addClass('visible'); // Change this line.
}, 1000 * i);
});
What I am trying to do is only run my code when someone has hovered on an element for 1 second.
Here is the code that I am using:
var timer;
$(".homeLinkWrap").mouseenter(function() {
timer = setTimeout(function(){
$(this).find('.homeLinkNfo').removeClass('flipOutY').addClass('flipInY').css({opacity: '1'});
console.log('in');
}, 1000);
}).mouseleave(function() {
$(this).find('.homeLinkNfo').removeClass('flipInY').addClass('flipOutY');
console.log('out');
clearTimeout(timer);
});
The first part (mouseenter) IS NOT functioning and DOESN'T remove the class and then add the new one. The second one (mouseleave) IS functioning properly and DOES remove the class and add the new one.
I am guessing it is because I am targeting $(this) which is the current element being hovered over and since it is in a timer function jQuery doesn't know which element $(this) is referring to.
What can I do to remedy this?
I think it is because you are calling $(this) inside the setTimeout function. You need to do something like this:
$(".homeLinkWrap").mouseenter(function() {
var $self = $(this);
timer = setTimeout(function(){
$self.find('.homeLinkNfo').removeClass('flipOutY').addClass('flipInY').css({opacity: '1'});
console.log('in');
}, 1000);
});
Inside the setTimeout callback, this no longer refers to the jQuery selection. You should either keep a reference to the selection:
$(".homeLinkWrap").mouseenter(function() {
var $this = $(this);
timer = setTimeout(function(){
$this.find('.homeLinkNfo').removeClass('flipOutY').addClass('flipInY').css({opacity: '1'});
console.log('in');
}, 1000);
})
Or use an arrow function (ES2015)
$(".homeLinkWrap").mouseenter(function() {
timer = setTimeout(() => {
$(this).find('.homeLinkNfo').removeClass('flipOutY').addClass('flipInY').css({opacity: '1'});
console.log('in');
}, 1000);
})
The problem here is that the this inside the callback function that you're passing to setTimeout doesn't reference to the same point that the this outside the callback does.
There are some ways of solving your problem, I'll suggest you to use Function.prototype.bind to bind your callback function to the same this you have outside:
var timer;
$(".homeLinkWrap").mouseenter(function() {
timer = setTimeout((function() {
$(this).find('.homeLinkNfo').removeClass('flipOutY').addClass('flipInY').css({ opacity: '1' });
}).bind(this), 1000);
}).mouseleave(function() {
$(this).find('.homeLinkNfo').removeClass('flipInY').addClass('flipOutY');
clearTimeout(timer);
});
i have 3 div elements with class name gridbox
i want to add a class into all 3 elements with delay.
for example:
new class should be added to all 3 div elements with a delay between each of them.
i triel following code which is not working.
$('.gridbox').addClass('animation').delay(1500);
What is wrong here?
You could try something like this:
var divs = $( '.gridbox' );
var index = 0;
var delay = setInterval( function(){
if ( index <= divs.length ){
$( divs[ index ] ).addClass( 'animation' );
index += 1;
}else{
clearInterval( delay );
}
}, 1500 );
What I'm doing here is this:
Extract all of the elements and store them in the divs variable.
Save an index of the element you are currently working with.
Initiate a setTimeout function with a delay of 1.5 seconds.
If we are not at the end of the list of elements, add the class to the relevant element after converting it to a jQuery element.
Increment our index variable.
Stop the setTimeout once we have iterated over all of the elements.
$('.gridbox').each(function(i) {
(function(self, j) {
setTimeout(function() {
$(self).addClass('animation');
},(j*1500)+1500);
})(this, i);
});
FIDDLE
$('.gridbox').each(function(index) {
var that = this;
setTimeout(function() {
$(that).addClass('animation');
}, 1500 * index);
});
if you want to apply a delay on a jquery function such as addClass you need to use a javascript setTimeout because as described here .delay() is limited and should be used for jQuery effects
You can try combination of .each() and setTimeout
$('.gridbox').each(function (index) {
var $this = $(this);
setTimeout(function () {
$this.addClass('animation');
}, 1500 * index );
});
Fiddle DEMO
a nicer solution :)
var st = setInterval(function(){
var gb = $('.gridbox:not(.animation):eq(0)');
gb.length > 0 ? gb.addClass('animation') : clearInterval(st);
},1500)
http://jsfiddle.net/jR984/
You can do this without jQuery
function addClass () {
var div = document.getElementsByClassName("aaa");
div[0].className = "bbb";
setTimeout(addClass, 1000);
}
window.onload = function () {
addClass();
}
http://jsfiddle.net/khGCv/
Although setTimeout/Interval kinda "works", jquery provides a much cleaner way to do custom animations: queue, for example:
$(".gridbox").each(function() {
var box = this;
$("body").queue(function(next) {
$(box).addClass("animation");
next();
}).delay(1000)
});
$('#test').hover(
function () {
$(this).append('Blah');
}
);
How can I make the jQuery repeatedly append Blah in #test based on how long you are hovering over #test?
For instance, how can I append Blah once every second you are hovering over #test?
You could use setInterval like this :
var myInterval = false;
$('#test').hover(
function(){
$that = $(this);
// need to save $(this) as 'this' will be different within setInterval
myInterval = setInterval(function(){
$that.append('Blah');
}, 100); // repeat every 100 ms
},function() {
clearInterval(myInterval); // clear the interval on hoverOut
}
);
Working example here
(function() {
var intv;
$('#test').hover(
function () {
var $this = $(this);
intv = setInterval(function() {
$this.append('Blah');
}, 1000);
},
function() {
clearInterval(intv);
}
);
}());
I've enclosed all the code inside a anonymous scoped function so to not pollute global scope, and I cached a reference to $(this) to avoid a new evaluation every second, inside the timeout
You can use setInterval to do so:
var appending; //var to store the interval
$('#test').hover(function(){ //on mouseenter
var $this = $(this); //store the context, i.e. the element triggering the hover
appending = setInterval(function(){ //the following function gets executed every second until the interval is cleared
$this.append('<p>Blah</p>'); //append content to context
},1000); //1000 meaning the repetition time in ms
},function(){ //on mouseleave
clearInterval(appending); //clear the interval on mouseleave
});
use setInterval()
$('#test').hover(
function () {
setInterval(function() {
$(this).append('Blah');
},1000)
}
);
I'm trying to create an animation sequence with jQuery where one animation starts after the previous one is done. But I just can't wrap my head around it. I've tried to make use of the jQuery.queue, but I don't think I can use that because it seems to have one individual queue for each element in the jQuery array.
I need something like:
$('li.some').each(function(){
// Add to queue
$(this).animate({ width: '+=100' }, 'fast', function(){
// Remove from queue
// Start next animation
});
});
Is there a jQuery way to do this or do I have to write and handle my own queue manually?
You can make a custom .queue() to avoid the limitless nesting..
var q = $({});
function animToQueue(theQueue, selector, animationprops) {
theQueue.queue(function(next) {
$(selector).animate(animationprops, next);
});
}
// usage
animToQueue(q, '#first', {width: '+=100'});
animToQueue(q, '#second', {height: '+=100'});
animToQueue(q, '#second', {width: '-=50'});
animToQueue(q, '#first', {height: '-=50'});
Demo at http://jsfiddle.net/gaby/qDbRm/2/
If, on the other hand, you want to perform the same animation for a multitude of elements one after the other then you can use their index to .delay() each element's animation for the duration of all the previous ones..
$('li.some').each(function(idx){
var duration = 500;
$(this).delay(duration*idx).animate({ width: '+=100' }, duration);
});
Demo at http://jsfiddle.net/gaby/qDbRm/3/
The callback of .animate() actually accepts another .animate(), so all you would have to do would be
$(this).animate({ width: '+=100' }, 'fast', function(){
$(selector).animate({attr: val}, 'speed', function(){
});
});
and so on.
You could call the next one recursively.
function animate(item) {
var elem = $('li.some').eq(item);
if(elem.length) {
elem.animate({ width: '+=100' }, 'fast', function() {
animate(item + 1);
});
}
}
animate(0);
why not build up a queue?
var interval = 0; //time for each animation
var speed = 200;
$('li.some').each(function(){
interval++;
$(this).delay(interval * speed).animate({ width: '+=100' }, speed);
});
EDIT: added speed param
Thanks to everybody replying!
I thought I should share the outcome of my question. Here is a simple jQuery slideDownAll plugin that slides down one item at a time rather than all at once.
(function ($) {
'use strict';
$.fn.slideDownAll = function (duration, callback) {
var that = this, size = this.length, animationQueue = $({});
var addToAnimationQueue = function (element, duration, easing, callback) {
animationQueue.queue(function (next) {
$(element).slideDown(duration, easing, function () {
if (typeof callback === 'function') {
callback.call(this);
}
next();
});
});
};
return this.each(function (index) {
var complete = null,
easing = 'linear';
if (index + 1 === size) {
complete = callback;
easing = 'swing';
}
addToAnimationQueue(this, duration / size, easing, complete);
});
};
} (jQuery));
Not very well test, but anyways.
Enjoy!!