DEV Community

sarandha
sarandha

Posted on

Need help in SvelteKit query based tab navigation.

Trying to create tab based navigation in sveltekit which loads data from +page.server.js based on what tab is selected. the active tab is selected from the url query ?mode=tabname . Below is the snippet taken from a large project but I narrowed the issue down to this boilerplate code.

+page.svelte

<script>
    import { page } from "$app/stores";

    export let data;

    $: mode = $page.url.searchParams.get("mode");
</script>

<section>
    <nav>
        <a href="?mode=list">list</a>
        <a href="?mode=add">add</a>
    </nav>
    {#if mode == "list"}
        <table>
            <tr>
                <th>id</th>
                <th>name</th>
            </tr>
            {#each data.list as l (l.id)}
                <tr>
                    <td>{l.id}</td>
                    <td>{l.name}</td>
                </tr>
            {/each}
        </table>
    {:else if mode == "add"}
        <form action="">
            <input type="text" name="name" />
            <button type="submit">save</button>
        </form>
    {:else}
        <b>Select an option from above</b>
    {/if}
</section>
Enter fullscreen mode Exit fullscreen mode

+page.server.js

export const load = async ({ url }) => {
    // maybe needed in both tabs.
    const info = {
        appname: "demo",
    };
    // only needed in "list" tab.
    const list = [
        { id: 1, name: "test one" },
        { id: 2, name: "test two" },
        { id: 3, name: "test three" },
    ];

    // Previously, I was returning all the data
    // without detecting any tab.
    // There was no problem with it apart from
    // performance issues
    // return {
    //     info,
    //     list,
    // };

    // seperating the returned data based on tab name
    // that's when the issue arise
    const mode = url.searchParams.get("mode");
    if (mode == "list") {
        return {
            info,
            list,
        };
    } else if (mode == "add") {
        return {
            info,
        };
    }};
Enter fullscreen mode Exit fullscreen mode

After navigation from 'list' to 'add' tab, this error is thrown in chrome console:

chunk-ERBBMTET.js?v=7f9a88c7:2609 Uncaught (in promise) Error: {#each} only works with iterable values.
    at ensure_array_like_dev (chunk-ERBBMTET.js?v=7f9a88c7:2609:11)
    at Object.update [as p] (+page.svelte:18:29)
    at Object.update [as p] (+page.svelte:12:35)
    at update (chunk-ERBBMTET.js?v=7f9a88c7:1351:32)
    at flush (chunk-ERBBMTET.js?v=7f9a88c7:1317:9)
Enter fullscreen mode Exit fullscreen mode

Looks like it's complaining about data.list even after navigation to the tab which does not even need data.list. returning both info and list object for every tab solves the issue and also wrapping the #each block in #if block does the trick eg:

{#if data.list}
    {#each data.list as l (l.id)}
      <tr>
        <td>{l.id}</td>
        <td>{l.name}</td>
      </tr>
    {/each}
{/if}
Enter fullscreen mode Exit fullscreen mode

Given that I'm not very experienced in SvelteKit, I not sure what am I doing wrong. Any help is appriciated. Thanks

Top comments (0)