Home > Software engineering >  Svelte store - all submitted array values get updated instead of one value
Svelte store - all submitted array values get updated instead of one value

Time:09-03

I am struggling to get my head around how to use stores, I am using a svelte store to create a simple todo array with prepopulated dummy data. I then want to use the store within the todo component displaying the dummy data and then updating when the user submits new data.

Now i can update the svelte store array, but when the user then adds another todo item it also updates the previously submitted value.

I have an interface entity called todo.ts which is implemented in the todo-store.ts i then access the store within the page.svelte and create a todo object to the hold the form data called todoItem i then pass this to the store when the submit button is pressed

Todo.ts

export interface ITodoItem {
    id: string;
    text: string;
    completed: boolean;
}

todo-store.ts

import { writable } from 'svelte/store';
import type { ITodoItem } from '../../entities/todo';

const todos: ITodoItem[] = [
    { id: '1', text: 'Todo 1', completed: true },
    { id: '2', text: 'Todo 2', completed: false },
    { id: '3', text: 'Todo 3', completed: false },
    { id: '4', text: 'Todo 4', completed: false },
  ]

export const todoList = writable<ITodoItem[]>(todos);

page.svelte

<script lang="ts">
    import { todoList } from './todo-store';
    import type { ITodoItem } from '../../entities/todo';

    let todoItem = <ITodoItem>{
        id: '',
        text: '',
        completed: false
    };

    const addToList = () => {
        $todoList = [...$todoList, todoItem];
    };
</script>

<h1>Todo List</h1>

<form on:submit|preventDefault={addToList}>
    <div>
        Id:<input type="text" id="id" bind:value={todoItem.id} />
    </div>
    <div>
        Todo:<input type="text" id="name" bind:value={todoItem.text} />
    </div>
    <div>
        <button>Submit</button>
    </div>
</form>

<hr />
{#each $todoList as item}
    <ul>
        <li>
            {item.text}
        </li>
    </ul>
{/each}

CodePudding user response:

The problem is, that you add a reference to the item to the list, so whenever you add an item, you actually add the same item over and over.

The fix is to copy the item when adding it, here a shallow copy is enough, which can be done by spreading the properties:

const addToList = () => {
    const newItem = { ...todoItem };
    $todoList = [...$todoList, newItem];
};

If you need a deep copy, you might want to use something like structuredClone.

  • Related