Svelte templates: loops
By Flavio Copes
Learn how to create loops in Svelte templates with the each block, getting the iteration index and adding a key to lists so updates stay reliable.
In Svelte templates you can create a loop using the {#each}{/each} syntax:
<script>
let goodDogs = ['Roger', 'Syd']
</script>
{#each goodDogs as goodDog}
<li>{goodDog}</li>
{/each}
If you are familiar with other frameworks that use templates, it’s a very similar syntax.
You can get the index of the iteration using:
<script>
let goodDogs = ['Roger', 'Syd']
</script>
{#each goodDogs as goodDog, index}
<li>{index}: {goodDog}</li>
{/each}
(indexes start at 0)
Why lists need a key
When dynamically editing the lists removing and adding elements, you should always pass an identifier in lists, to prevent issues.
Here’s the problem. Without a key, Svelte matches list items to DOM nodes by position. Remove the first dog from the array, and Svelte doesn’t remove the first <li>. It updates every <li> in place to show the shifted data, and drops the last one.
Usually you won’t notice. But if the items hold state that lives in the DOM, like an input value, a checkbox, or a running transition, that state stays attached to the wrong item. You delete Roger and suddenly Syd has Roger’s half-typed input.
A key tells Svelte which DOM node belongs to which data item, so it moves and removes the right ones.
You do so using this syntax:
<script>
let goodDogs = ['Roger', 'Syd']
</script>
{#each goodDogs as goodDog (goodDog)}
<li>{goodDog}</li>
{/each}
<!-- with the index -->
{#each goodDogs as goodDog, index (goodDog)}
<li>{goodDog}</li>
{/each}
The part in parentheses is the key expression. Here we use the string itself, which works because each dog name is unique.
You can pass an object, too, but if your list has a unique identifier for each element, it’s best to use it:
<script>
let goodDogs = [
{ id: 1, name: 'Roger'},
{ id: 2, name: 'Syd'}
]
</script>
{#each goodDogs as goodDog (goodDog.id)}
<li>{goodDog.name}</li>
{/each}
<!-- with the index -->
{#each goodDogs as goodDog, index (goodDog.id)}
<li>{goodDog.name}</li>
{/each}
Watch out: don’t use index as the key. It defeats the purpose, because after removing an item the indexes shift and Svelte is back to matching by position.
Showing something when the list is empty
An each block can have an {:else} section, rendered when the array has no items:
{#each goodDogs as goodDog (goodDog.id)}
<li>{goodDog.name}</li>
{:else}
<p>No dogs yet!</p>
{/each}
Handy for empty states, with no separate {#if} block needed.
Related posts about svelte: