Search code examples
selectsvelteweb-componenttwo-way-bindingshoelace

Empty Shoelace Select with two way binding in Svelte


I cannot empty previous selection when changing options between related Shoelace Selects in Svelte. I tried to force Shoelace select value but it didn't work, maybe I shouldn't use two-way binding or there is another workaround when working with Shoelace and Svelte.

I have an array of trees, where trees have branches.

<script>
    import { trees } from './data'
    import Select from './Select.svelte'
    
    let id_trees = '1'
    let id_branches = '1'
    
    $: branches = trees.find(tree => tree.id == id_trees).branches
</script>


<Select label="Trees" bind:value={id_trees}>
   {#each trees as { id, name }}
     <sl-option value={id}>{name}</sl-option>
   {/each}
</Select>

<Select label="Branches" bind:value={id_branches}>
   {#each branches as { id, name }}
     <sl-option value={id}>{name}</sl-option>
   {/each}
</Select>

If I change from tree A to B and C render works as expected:

enter image description here

but if I go back to tree A then branch C1 remains:

enter image description here

Here a minimal working example:

https://svelte.dev/repl/367d0371c1c34b09912f3a2a381c8234?version=4.2.10

Update: variable for the branch selection remains the same

key and object identity solutions are wonderful but they only affects the render. I though using object identity would empty the real value but it doesn't. How can we empty the id_branches selection?

Same working example where I chose different ids to show that changing trees doesn't empty/change id_branches:

https://svelte.dev/repl/94f43b27eb22435198643b2fe92206b5?version=4.2.10

Solution:

brunnerh answer and comments solved the issue!


Solution

  • The component does not appear to update based on the text content change of the option (the value potentially remains the same).

    In situations like this, a simple workaround is to recreate the affected part of the component via {#key}. So in this case you could do this:

    {#key branches}
        <Select label="Branches" bind:value={id_branches}>
           {#each branches as { id, name }}
                 <sl-option value={id}>{name}</sl-option>
           {/each}
        </Select>
    {/key}
    

    This way, the dependent select is fully updated if its options list changes.


    You also can force the recreation of the options in the {#each} by providing a key (see docs) that can distinguish between the branch items of the different trees, e.g. by using the object identity of the items:

    <Select label="Branches" bind:value={id_branches}>
       {#each branches as item (item)}
         {@const { id, name } = item}
         <sl-option value={id}>{name}</sl-option>
       {/each}
    </Select>
    

    This however will cause the selection to be cleared on tree change, even if the option value would exist.