When reading Svelte 3 documentation of the {#each}
keyword, it isn't clear how to correctly handle the case where the variable we want to iterate on is null
or undefined
.
A common use case is listing the result of an object of type Promise<MyItem[]>
. We could imagine for example that this promise represents the result of an HTTP request. We would first initialized the promise to null
as a way to communicate that we didn't fetch any result yet.
A basic version that doesn't handle empty or false-y results would look like this:
<script lang="ts">
import { storeRequestResults } from "./stores"
</script>
<ul>
{#await $storeRequestResults}
<p>loading...</p>
{:then result}
{#each result as item}
<li>{item}</li>
{/each}
{:catch error}
<pre>{error}</pre>
{/await}
</ul>
Unfortunately when {:then result}
is facing a null
or undefined
value, the Svelte template will fail with a runtime error: "Uncaught Error: {#each} only iterates over array-like objects".
The error message is clear enough, #each
only deals with arrays.
We could fix it by changing our initialization value, or add an {#if result}
block around the {#each}
, but there is a simplest solution that only has very little downside: use the ||
operator to default to an empty array.
That does look like this:
{#await $storeRequestResults}
...
{:then result}
<!-- 1. Use the logical OR operator to default to an empty array if 'result' is false-y
👇 -->
{#each result || [] as item}
<li>{item}</li>
<!-- 2. Use the `:else` clause to handle the case where the array is empty -->
{:else} <!-- 👈 -->
<li>No items found<li/>
{/each}
{:catch error}
...
{/await}
I hope that helps some of you, it's a nice trick to know!