0

This is my first time building a loop in jQuery or js, and I've gotten myself over my head.

I have a piece of content that needs to loop on page load:

<li id="nav_about"><a href="">Loren ipsum <span id="adjective">1</span></a>
</li>

At a regular interval to go down the following functions (swapping text out), and then once the loop reaches the last function, to return to the top and start it all over again.

{$("#adjective").fadeOut(500).delay(100).text("2").fadeIn(500);}
{$("#adjective").fadeOut(500).delay(100).text("3").fadeIn(500);}
{$("#adjective").fadeOut(500).delay(100).text("4").fadeIn(500);}
{$("#adjective").fadeOut(500).delay(100).text("1").fadeIn(500);}

I know I need to use setInterval, define a variable, and create a function here somehow, but honestly I'm lost as to how the pieces go together.

My gut level guess is that even this is a rather clunky way of achieving this, and there's likely a method of defining the .text terms as variables in an array as to avoid the multiple .fadeOuts and .fadeIns.

Could sure use some help here.

Ariel
  • 25,995
  • 5
  • 59
  • 69
Will Phillips
  • 145
  • 2
  • 8
  • you may find the following useful as a starter - http://stackoverflow.com/questions/914951/show-and-hide-divs-at-a-specific-time-interval-using-jquery/915016#915016 – Russ Cam Oct 24 '11 at 22:34

4 Answers4

2

Here's a way of doing what (I think) you want.

http://jsfiddle.net/bryanjamesross/kdbYk/

Your gut instinct was correct. However, notice how I had to use a callback on the fadeout. That's required because for some reason putting the text() call in the chain caused it to wait until all animation had finished before changing the text.

rossipedia
  • 56,800
  • 10
  • 90
  • 93
  • In a word: elegant. Damn elegant. Now It's time for me to work back, reverse engineer the damn thing, and teach myself how it works. Thanks a bunch! – Will Phillips Oct 25 '11 at 08:43
1

You are not doing this correctly. You don't want setInterval here.

The first thing you need to know is that the way your wrote it, all of these command will run simultaneously meaning you will be fading in and out at the same time (which is going to look odd). When you chain command they don't wait - they all run at the same time. Instead you use the callback feature, when each animation is done it calls the callback which does the next step.

Change it to this:

function fader(text, next) {
  $("#adjective").fadeOut(500, function() {
    $(this).text(text).delay(100).fadeIn(500, function() {
      next();
    });
  });
}

function fader2() { fader('2', fader3); }
function fader3() { fader('3', fader4); }
function fader4() { fader('4', fader1); }
function fader1() { fader('1', fader2); }

fader2();

The fader function does each step of the animation. Then when the final animation is done it calls the function passed in as next to continue the loop.

Then I setup a bunch of functions to define the sequence (I'm sure there are other ways to do this - an array perhaps, but this was the first that came to mind).

PS. I didn't test this, there may be typos.

Ariel
  • 25,995
  • 5
  • 59
  • 69
  • Even though I answered below, this is definitely the more jQuery and Javascript way of doing this. – rossipedia Oct 24 '11 at 22:49
  • Are you sure there is a completion function for the delay() method? I don't see it in the [jQuery docs for `.delay()`](http://api.jquery.com/delay/)? – jfriend00 Oct 24 '11 at 23:03
  • FYI, I looked in the jQuery 1.6.2 source and I don't see any support for a completion function on `.delay()`. I don't think this will work. – jfriend00 Oct 24 '11 at 23:09
  • @jfriend00 now that is interesting. My first time seeing delay. Ok, I have modified my answer to use it. You can't just chain everything using a delay to space things because the `text()` will be executed too early - you have to change the text in a callback. However you can use `delay()` to avoid making huge callback chains, but you will need to do the math, each delay will have to increase by the TOTAL time of ALL preceding animations. – Ariel Oct 24 '11 at 23:11
  • @Ariel Ahhh... so I DID cover that in my answer! I knew it :) – rossipedia Oct 26 '11 at 06:21
0

The first thing you should do is break this out into parts. Instead of working on the automatic looping first work on getting the function working first then call it in a loop.

start by making this function work:

function myLoop(){ 
  var max = 4
  var min = 0
  // find the element and decrement it's value
  // if the element's value is below the minimum, set it to the maximum
}

and hook its execution up to a button press:

$("#myButton").live("click", myLoop);

then when you have the function working correctly with every button press, get it running in a timed loop:

setInterval(myLoop, /*time in milliseconds*/)
greggreg
  • 11,945
  • 6
  • 37
  • 52
0

You don't need setInterval here. You can just run the sequence and then start the next sequence when the previous one finishes.

Here's one way to do it using completion functions to kick off the next operation after the animation concludes. You can see it work here: http://jsfiddle.net/jfriend00/PTZXV/.

The code is this:

function cycle(cntr) {
    if (cntr > 4) { cntr = 1; }
    var o = $("#adjective");
    o.fadeOut(500, function() {
        o.text(cntr + "").delay(100).fadeIn(500, function() {
            cycle(++cntr);
        });
    });
}

cycle(2);

FYI, you can't use sequences like this:

$("#adjective").fadeOut(500).delay(100).text("2").fadeIn(500);

The delay(100) methods only work between methods that are in the fx animation queue and the .text("2") operation doesn't use the fx animation queue so it won't be sequenced properly with the other operations. That's why I had to use completion functions before and after the .text() method.

Edit: To make an operation go through the animation queue (so it will respect the .delay() methods and other sequencing in the animation queue), you can use the .queue() method. You could do that like this:

function cycle(cntr) {
    if (cntr > 4) { cntr = 1; }
    var o = $("#adjective");
    o.fadeOut(500)
        .queue(function(next) {o.text(cntr + ""); next();})
        .delay(100)
        .fadeIn(500, function() {cycle(++cntr);});
}

cycle(2);

Which you can see working here: http://jsfiddle.net/jfriend00/mkyTQ/.

jfriend00
  • 683,504
  • 96
  • 985
  • 979