90

I'm grabbing an array of jQuery objects and then via .each() modifying each individual jquery with in the array.

In this case I'm updated the class names to trigger a -webkit-transition-property to utilize a css transition.

I'd like there to be a pause before each css transition begins. I'm using the following, but there is no delay in between each update. Instead, they all appear to be updating at once.

function positionCards() {
  $cards = $('#gameboard .card');
  $cards.each(function() {
      setTimeout( function(){ addPositioningClass($(this)); }, 500 )
  });
}

function addPositioningClasses($card){
  $card
    .addClass('position')
}

I was hoping setTimeout would solve this, but it doesn't seem to be working. Is there a way to accomplish the pause before each CLASS name update of each object?

DA.
  • 39,848
  • 49
  • 150
  • 213
  • try using quotes around the addPositioningClass function, like this: setTimeout( 'addPositioningClass($(this))', 500 ) – amosrivera Mar 05 '11 at 07:38
  • 1
    could you increment the timeout for each iteration say 500,1000,1500... – Rob Mar 05 '11 at 07:42

8 Answers8

108

I added this as a comment but now that I have read it correctly and answered my own question this would probably work:

function positionCards() {
  var $cards = $('#gameboard .card');

  var time = 500;

  $cards.each(function() {
      setTimeout( function(){ addPositioningClass($(this)); }, time)
      time += 500;
  });
}
    
Rob
  • 10,004
  • 5
  • 61
  • 91
  • 1
    How is your code any different than the OP? There is a scope error because `addPositioningClasses` doesn't exist in the context of `setTimeout` – JohnP Mar 05 '11 at 07:55
  • @JohnP - @DA states that the code works but that all the elements are positioned at once, I wasn't aware that the scope of the function was part of the problem... – Rob Mar 05 '11 at 07:58
  • 1
    I just tried it in a fiddle and it doesn't work. I may be mistaken, but I can't see how that code can work at all. – JohnP Mar 05 '11 at 08:00
  • 3
    @JohnP - @DA said --> "I'm using the following, but there is no delay in between each update. Instead, they all appear to be updating at once." – Rob Mar 05 '11 at 08:06
  • @DA can you please clarify whether the current `setTimeout()` works or not? @Rob, I've removed my -1 just in case :) – JohnP Mar 05 '11 at 08:08
  • This was the solution! The difference is that I was setting everything to have a timeout of 500. Because they execute at the same time, there wasn't a delay between them. By incrementing the timeout by 500 for each item, you then get the visual delay. thanks, Rob! – DA. Mar 05 '11 at 18:53
  • 2
    Solution: which is also present in this Git: https://gist.github.com/Zackio/7648481 – Pranesh Janarthanan Aug 22 '18 at 14:04
  • 1
    When I try, $(this) is the window. Within my each() function, it is the element but inside of the setTimeout, it is the window. I cannot seem to pass the element to the setTimeout's function! – twistedpixel Jun 02 '22 at 11:07
53

Sorry for digging up an old thread, but this tip could be useful for similar issues:

$cards.each(function(index) {
    $(this).delay(500*index).addClass('position');
});
Justin Nimmo
  • 125
  • 12
johnjohn
  • 555
  • 4
  • 2
  • 6
    Beware that `delay` is meant only for the animation queue and **wont** work on e.g. `css()` (see [here](http://stackoverflow.com/a/5396158/2295964)) – Yan Foto Jan 20 '15 at 13:29
  • 22
    You have to use `.queue()` (and `.dequeue()`) when delaying `.addClass()`: `$(this).delay(500*index).queue(function() { $(this).children('.flipcontainer').addClass('visible').dequeue(); });` – aksu Jun 02 '15 at 17:36
  • 2
    @aksu You should copy what you have there and make it into an answer, because it's lost amongst the comments and your answer helped me make it work properly. – adamj Apr 28 '17 at 03:19
11

If you make a method that calls itself every 500 ms that should do that trick. The following code should work.

var __OBJECTS = [];

$('#gameboard .card').each(function() {
    __OBJECTS.push($(this));
});

addPositioningClasses();

function addPositioningClasses() {
    var $card = __OBJECTS.pop();
    $card.addClass('position');
    if (__OBJECTS.length) {
        setTimeout(addPositioningClasses, 500)
    }
}

Tested on fiddle : http://jsfiddle.net/jomanlk/haGfU/

JohnP
  • 49,507
  • 13
  • 108
  • 140
3

How about .delay() ?

or

function addPositioningClasses($card){
  setTimeout(function() { $card.addClass('position')}, 1000);
}
xkeshav
  • 53,360
  • 44
  • 177
  • 245
1

If you're only targeting Safari/iOS, depending on how important it is to you to control the exact timing of animation sequences, you should maybe avoid any solution that involves JS timeouts. There is no guarantee that the animation will complete at the same time as the timeout delay, particularly on slow processors or machines that have lots of stuff going on in the background. Later versions of webkit (including mobile safari) do allow for timed animation sequences via @-webkit-keyframes. Webkit.org has a nice intro to it. It's actually pretty easy to implement.

Andrew
  • 14,204
  • 15
  • 60
  • 104
  • I am, indeed, only targetting iOS (it's an app). I'm not timing the animation sequence, but, rather, timing how long to wait until to update the class name, which then, in turn, triggers a webkit transition css. – DA. Mar 05 '11 at 18:57
1

Give this a try:

function positionCards() {
  $('#gameboard .card').each(function() {
      $(this).delay(500).addClass('position');
  });
}

I'll be honest... I've had $(this).delay() misbehave in the past in certain instances and work flawlessly in others. However, this was normally in conjunction with jQuery animation calls, not DOM attribute manipulation.

Please be aware .delay() does not function in the same way as setTimeout. For more information, see the jQuery .delay() documentation.

As far as I am aware, $().each does execute procedurally so the next iteration of the call should only begin after the preceding has completed.

lsuarez
  • 4,952
  • 1
  • 29
  • 51
  • I may be wrong, but in reading the jquery documentation, it look slike delay is only for delaying jQuery animations. I think you are also correct in that last paragraph. The thing was that I wasn't delaying the function call that set the class, but rather I was delaying when the class would be set. So, it applied the delay to all 30 elements at the same time, and they all then delayed the same amount of time. – DA. Mar 05 '11 at 18:55
0

Check this out, worked well for me! :)

jQuery('.optiresultsul li').each(function(index) {
    jQuery(this).delay(500*index).animate({ opacity: 1 }, 500,function(){
        jQuery(this).addClass('bgchecked');
    });
});
-2

This code will add set the inital delay to 50ms. Then for each loop through the ".row" class it will add an additional 200ms delay. This will create a nice delayed show effect for each row.

$( document ).ready(function() {
    // set inital delay
    var dtotal = 50;
    $(".row").each(function() {
    //add delay to function
      $(this).delay(dtotal).show();
    //add 200ms to delay for each loop
      dtotal = dtotal + 200;
    });
});
LeeF
  • 9
  • 2