2

I'm trying to animate a logo. The markup looks like this:

<div id="logo">
    <h1>
        <span>A</span><span>n</span><span>t</span><span>o</span><span>n</span><span>i</span><span>o</span><span>R</span><span>o</span><span>s</span><span>s</span><span>i</span>
    </h1>
    <h2>composer</h2>
</div>

What I'm trying to do is to make a fade-in effect for each <span> inside #logo. To do so, I'm using this code:

function fadeInRecursive (elementToFade) {

    if (!elementToFade) {
        elementToFade = $('#logo span:first-child')
    }

    var next = elementToFade.next('#logo span')

    if (!next) {return false}

    elementToFade.animate({
        opacity: 1
    }, 3000, fadeInRecursive(next))
}

$(document).ready( fadeInRecursive )

But Firefox crashes...

What am I doing wrong?

Simone
  • 20,302
  • 14
  • 79
  • 103
  • I think you want `$(document).ready( fadeInRecursive );` without the `()` - that *calls* the function, but you just want to *refer to* the function. – Pointy Jun 13 '12 at 17:01
  • Also, declare "next" with `var` !! ... oh wait; is it supposed to be global? Well, declare it with `var` at the global scope, or wrap that all in a closure. – Pointy Jun 13 '12 at 17:01
  • 5
    Oh man, I can't look at code with no semi colons... – chrisfrancis27 Jun 13 '12 at 17:02
  • Could you be a little clearer about what "crashes" means? Are you saying that this causes the browser process to fail entirely? Or do you just get an error? If an error, what exactly is it? – Pointy Jun 13 '12 at 17:03
  • Does it burn on the crash so you get a burning Firefox? – Mark Schultheiss Jun 13 '12 at 17:06
  • @Pointy thanks! I've updated my code. Before the console was saying `too much recursion`. Now the error is: `elementToFade.next is not a function` – Simone Jun 13 '12 at 17:09
  • 1
    that's a lot of span elements: sure you don't want js to do that for you? http://jsfiddle.net/vzgBd/5/ (based on jfriend00, answer). – demux Jun 13 '12 at 17:33
  • @ChrisFrancis Does it still work? – Playmaker Jun 13 '12 at 19:33
  • Yeah it's technically valid (in MOST cases), but relying on line-breaks to signify the end of a statement just feels hacky to me - the semi-colon gives a definitive end! And there are [some edge cases](http://stackoverflow.com/a/1169596/752213) where the code will be interpreted in a completely different way – chrisfrancis27 Jun 14 '12 at 09:06

2 Answers2

3

Here's a generic function that will fade in each item in a selector, one after the other:

function fadeInSuccessive(selector, t) {
    var items = $(selector);
    var index = 0;

    function next() {
        if (index < items.length) {
            items.eq(index++).fadeIn(t, next);
        }
    }
    next();
}

fadeInSuccessive("#logo span", 1000);

And a working demo: http://jsfiddle.net/jfriend00/vzgBd/

This doesn't actually use recursion (though it might look like it) because the successive call to next() happens some time later triggered by the completion of the animation and when it's called, the previous call to next() has already completed so it isn't technically recursion.


And here's an even more generic implementation done as a jQuery method:

$.fn.fadeInSuccessive = function(t, fn) {
    var index = 0;
    var self = this;

    function next() {
        if (index < self.length) {
            self.eq(index++).fadeIn(t, next);
        } else {
            if (fn) {
                fn.call(self);
            }
        }
    }
    next();
}

$("#logo span").fadeInSuccessive(1000, function() {
    $(document.body).append("<br>Done!");
});

A a working demo: http://jsfiddle.net/jfriend00/zTURy/

jfriend00
  • 683,504
  • 96
  • 985
  • 979
2

You can avoid recursion by putting elements in a queue:

$("#logo span").each(function(n, e) {
    $(e).hide();
    $("#logo").queue(function() { $(e).fadeIn(function() { $("#logo").dequeue()}) });            
});

http://jsfiddle.net/YmVrQ/

And here's a "recursive" approach:

function fadeInRecursive (elems) {
    if (elems)
        $(elems.shift()).fadeIn(function() { fadeInRecursive(elems) });
}

fadeInRecursive($.makeArray($("#logo span")));

Or in the spirit of what jfriend00 has posted:

var n = 0;
(function () { $("#logo span").eq(n++).fadeIn(arguments.callee) })();
georg
  • 211,518
  • 52
  • 313
  • 390