Previously, I covered how if-else logic works in Svelte. Today, I'll be going over how to use each logic in Svelte, letting us iterate over objects to display their contents.
If you're new to Svelte, read my guide on how to create your first Svelte project here.
Motivation for each logic in Svelte
Let's say we are making a component in Svelte, as covered in my guide on Svelte components. We have a set of data, and some basic CSS. In Svelte, this looks like a normal HTML/CSS/Javascript file:
<script>
let locations = [
{
country: "UK",
city: "London",
},
{
country: "India",
city: "Mumbai"
},
{
country: "France",
city: "Paris"
}
];
</script>
<div id="data">
</div>
<style>
#data {
padding: 2rem;
border-radius: 10px;
border: 1px solid #eee;
}
</style>
Without Svelte, if we want to display all of that data we would have to do a loop through it and generate the HTML with Javascript. With Svelte, it's much easier to loop through data - we simply use {#each}
logic.
How each Logic in Svelte Works
With each, we can take our #data div and iterate through our locations object right within it.
The each loop in Svelte has the following syntax:
{#each locations as { country, city }, i}
|-----|--------| |---------------| ^
| | | └ - - - the index of the current item
| | └ - - - all the properties we want to access from "locations"
| └ - - - the variable in our Javascript to iterate over
└ - - - the start of the each block
Essentially, we can deconstruct our locations function into however many properties we want to display. If we wanted to only show country, we could write {#each locations as { country }, i}
.
We can even entirely leave out i, and just write {#each locations as { country, city }}
.
Using each Logic in Svelte
Let's look at an example. Below, I've turned our location list into HTML using each logic:
<script>
let locations = [
{
country: "UK",
city: "London",
},
{
country: "India",
city: "Mumbai"
},
{
country: "France",
city: "Paris"
}
];
</script>
<div id="data">
{#each locations as { country, city }, i}
<div class="county-city">
{i + 1}: {country}, {city}
</div>
{/each}
</div>
<style>
#data {
padding: 2rem;
border-radius: 10px;
border: 1px solid #eee;
}
</style>
The above code will produce the following output:
1: UK, London
2: India, Mumbai
3: France, Paris
Svelte makes this super easy, and gives us the flexibility to leave data out. For example, here is an example displaying country only, with no index:
<script>
let locations = [
{
country: "UK",
city: "London",
},
{
country: "India",
city: "Mumbai"
},
{
country: "France",
city: "Paris"
}
];
</script>
<div id="data">
{#each locations as { country }}
<div class="county-city">
{country}
</div>
{/each}
</div>
<style>
#data {
padding: 2rem;
border-radius: 10px;
border: 1px solid #eee;
}
</style>
The above code will produce the following output:
UK
India
France
Keyed each Blocks in Svelte
If we want to access the entire object, Svelte also gives us that option. For example, instead of writing {#each locations as {country, city}, i}
, we can simply write:
{#each locations as location, i}
Let's look at an example. The code below works exactly the same as previous examples, but instead of directly referencing country, we write location.country. Both ways are the same, so it's up to you which you prefer to use. Some people prefer this version, due to its simplicity as you don't have to redefine constantly which elements from the object to use:
<script>
let locations = [
{
country: "UK",
city: "London",
},
{
country: "India",
city: "Mumbai"
},
{
country: "France",
city: "Paris"
}
];
</script>
<div id="data">
{#each locations as location, i}
<div class="county-city">
{i + 1}: {location.country}, {location.city}
</div>
{/each}
</div>
<style>
#data {
padding: 2rem;
border-radius: 10px;
border: 1px solid #eee;
}
</style>
Keyed each Statements in Svelte
If you already have predefined identifiers, you can pass these to Svelte along with the index. The benefit of this is that if data should be updated or changed, you retain a strong link between the original data set, and Svelte will use it to diff the list if data changes, rather than adding or removing something to the end.
A good way to think about this is that if you provide a key you are telling Svelte to map HTML elements to that key. If the item with the key is removed, it will remove the DOM element. If the properties change for that key, then Svelte will update DOM element.
If instead you don't provide a key, Svelte goes off the array index. That can lead to some problems - if we remove an element from the start, for example, the first DOM element will simply be updated with properties from the "new" first item in the array. As such it can be useful to use a unique key.
How to use Keyed each Statements in Svelte
let locations = [
{
id: "123-123-123",
country: "UK",
city: "London",
},
{
id: "124-124-124",
country: "India",
city: "Mumbai"
},
{
id: "125-125-125",
country: "France",
city: "Paris"
}
];
We could then define id as our unique key for each item. If we wanted to do that, it'd look like this:
{#each locations as location, i (location.id)}
Or, if we're deconstructing, we could also write it like this:
{#each locations as {id, country, city}, i (id)}
Or finally, we can remove i altogether - and simply refer to id. This will let us use our id in code, and also link the DOM element to our id property:
{#each locations as {id, country, city} (id)}
Using this in code, we can still achieve the same results, but we will have hard linked our DOM elements to particular array elements:
<script>
let locations = [
{
id: "123-123-123",
country: "UK",
city: "London",
},
{
id: "124-124-124",
country: "India",
city: "Mumbai"
},
{
id: "125-125-125",
country: "France",
city: "Paris"
}
];
</script>
<div id="data">
{#each locations as location, i (location.id)}
<div class="county-city">
{i + 1}: {location.country}, {location.city}
</div>
{/each}
</div>
<style>
#data {
padding: 2rem;
border-radius: 10px;
border: 1px solid #eee;
}
</style>
Each-else statements in Svelte
We can define default behaviour for an empty list using the {:else}
statement. Simply define your {#each}
statement as normal, and add it in after. It will only display if the list is empty.
Here is an example:
<div id="data">
{#each locations as location, i (location.id)}
<div class="county-city">
{i + 1}: {location.country}, {location.city}
</div>
{:else}
<div class="empty-list">No items to show!</div>
{/each}
</div>
Top comments (0)