Search code examples
javascriptsveltesveltekit

Transition delay ignored in loop


There is a component that has fade transition with delay applied. Works as expected unless it is put inside a loop. In that case it ignores the delay property.

Code of the component:

<div in:fade={{ delay: delayPlus(), duration: 1500 }}>
    <p>{word}</p>
</div>

Delay value incrementor:

function delayPlus() {
    let delay: number = 0;
    count.subscribe((value) => (delay = value));
    count.update(() => delay + (Math.floor(Math.random() * 451) + 50));
    return delay;
}

Components are rendered in respect to the delay property when used as:

<div in:fade={{ delay: delayPlus(), duration: 1500 }}>
    <p>{words[0]}</p>
</div>
<div in:fade={{ delay: delayPlus(), duration: 1500 }}>
    <p>{words[1]}</p>
</div>
<div in:fade={{ delay: delayPlus(), duration: 1500 }}>
    <p>{words[2]}</p>
</div>
<div in:fade={{ delay: delayPlus(), duration: 1500 }}>
    <p>{words[3]}</p>
</div>

However if they are rewritten into a loop they appear immediately respecting only the duration property:

{#each words as word}
    <div in:fade={{ delay: delayPlus(), duration: 1500 }}>
        <p>{word}</p>
    </div>
{/each}

Is this a standard behaviour? What is the catch to make the loop behave as expected in first example?


Solution

  • It's not ignoring anything, that is how it's supposed to work. It's supposed to display after a delay of 1500 ms regardless of it being in a loop or not. To have them displayed by a delay of 1500 ms one after the other, utilize the index of every iteration by adding one to it and multiplying it by 1500. So, for example, for the first iteration, it should do 1500 * 1, 1500 MS, for the second one, it should do 1500 * 2, 3000 MS, and so on. I am not a Svelte user so I don't know how it looks like in code but you can do it in, say, a vanilla JavaScript map function like so:

    const iterable = ["after 1500 ms", "after 3000 ms", "after 4500 ms"]
    
    iterable.map((element, index) => {
      setTimeout(() => {
        console.log(element)
      }, 1500 * (index + 1));
    });
    

    Just reform the code to make it work with your Svelte components, should work the same.