I am going through the article " Componentizing our Svelte app" and in the section Extracting our filter component they created a FilterButton.svelte
component and in this component, there is an on click event which is changing the top level filter
variable inside the current component.
<script>
export let filter = 'all'
</script>
<div class="filters btn-group stack-exception">
<button class="btn toggle-btn" class:btn__primary={filter === 'all'} aria-pressed={filter === 'all'} on:click={() => filter = 'all'} >
<span class="visually-hidden">Show</span>
<span>All</span>
<span class="visually-hidden">tasks</span>
</button>
<button class="btn toggle-btn" class:btn__primary={filter === 'active'} aria-pressed={filter === 'active'} on:click={() => filter = 'active'} >
<span class="visually-hidden">Show</span>
<span>Active</span>
<span class="visually-hidden">tasks</span>
</button>
<button class="btn toggle-btn" class:btn__primary={filter === 'completed'} aria-pressed={filter === 'completed'} on:click={() => filter = 'completed'} >
<span class="visually-hidden">Show</span>
<span>Completed</span>
<span class="visually-hidden">tasks</span>
</button>
</div>
The problem is that this only changes the filter
variable inside the current component so they used bind:filter={filter}
in the parent component call to update the parent’s filter variable when changed in the child component.
<FilterButton bind:filter={filter} />
It makes sense to me and is easy to reason about but later in the section Creating our Todo component they created Todo.svelte
component and this component receives a single object todo as a prop and uses its properties inside this component.
<script>
export let todo
</script>
<div class="stack-small">
<div class="c-cb">
<input type="checkbox" id="todo-{todo.id}"
on:click={() => todo.completed = !todo.completed}
checked={todo.completed}
/>
<label for="todo-{todo.id}" class="todo-label">{todo.name}</label>
</div>
<div class="btn-group">
<button type="button" class="btn">
Edit <span class="visually-hidden">{todo.name}</span>
</button>
<button type="button" class="btn btn__danger" on:click={() => alert('not implemented')}>
Delete <span class="visually-hidden">{todo.name}</span>
</button>
</div>
</div>
In the parent, we have an array of objects which we loop using {#each}
and on each iteration, we are calling the Todo.svelte
component and passing a todo as prop
<ul role="list" class="todo-list stack-large" aria-labelledby="list-heading">
{#each filterTodos(filter, todos) as todo (todo.id)}
<li class="todo">
<Todo {todo} />
</li>
{:else}
<li>Nothing to do here!</li>
{/each}
</ul>
My confusion is in this part is that the Todo.svelte
component also has an on click event which toggles the completed property of the todo object inside the current component. But when I use filters it filters the todo as expected but why and how the onlick event inside the Todo.svelte component is updating the completed property of its parent todo object which is just a prop coming from Todos.svelte in this case.
We are not using bind:todo={todo}
in order to also update the todo in the parent component so how Svelte is doing it is hard to reason about.
I hope my question makes sense and hope to get an answer. Thank you.