Search code examples
javascriptarrayssveltestore

Toggle add/remove items to a writable array store in Svelte


I have a Svelte store that's a writable array.

To begin, I have a separate array of names, and am using that to populate a selection panel the user can click on.

The idea is that if they click on the name, it will appear below and be added to the array store.

All of this works as I want. However, if a user name is already in the store, I want to then remove that name.

I have looked at other examples, but have only been able to make it so the name doesn't get added again. I can't remove the name if it's already in the store. I'd appreciate any help.

My code is below, but I've also created a REPL: https://svelte.dev/repl/4db04c20d9c94f49832584cf405fdb59?version=3.58.0

app.svelte file:

<script>
    import { list } from './plus.js';
    
    let people = [
        {id: 1, name: "John"},
        {id: 2, name: "Sue"},
        {id: 3, name: "Bill"},
    ]
        
    const addToList = (person) => {
        console.log('person',person)
        console.log('len', $list.filter(e => e.name === person.name).length)
        
        if ($list.filter(e => e.name === person.name).length > 0) {
            console.log('remove name if it exists in array already')
            $list = $list.filter((listItem) => listItem != person.name)
    }else{
            console.log('add name to array if not there')
            $list = [...$list, person]          
        }
    }
    
</script>

<div class="person-list">
    {#each people as person}
    <div>
    <h4>{person.name}</h4>
    <button on:click={() => addToList(person)}>●</button>
    </div>
    {/each}
</div>

{#each $list as item}
    <p>
        {item.name}
    </p>
{/each}

plus.js file:

import { writable } from 'svelte/store';

export const list = writable([]);

Solution

  • The filter condition is just wrong, it compares the entire item with the name, it should be:

    $list.filter(listItem => listItem.name != person.name)
    

    If you remove items at arbitrary positions, you should also add a key to the #each:

    {#each $list as item (item.name)}