I am working on a small ToDo application in Svelte for learning purposes (Im new to Svelte).
In the view I have:
<div class="input-group p-2" id="editForm">
<input type="text" class="form-control" id="old_todo" value={currentToDo.title} placeholder="Edit Todo">
<div class="input-group-append">
<button on:click="{addTodo}" class="btn btn-sm btn-success">Save</button>
</div>
</div>
//More code
{#each todos as t, index}
<tr>
<td>{index + 1}</td>
<td class="{t.completed == true ? 'completed' : ''}">{t.title}</td>
<td class="text-center"><input type="checkbox" on:change={completeTodo(t.id)}></td>
<td class="text-right">
<div class="btn-group">
<button on:click="{editTodo(t.id)}" class="btn btn-sm btn-primary">Edit</button>
<button on:click="{deleteTodo(t.id)}" class="btn btn-sm btn-danger">Delete</button>
</div>
</td>
</tr>
{/each}
The part of the script I believe is relevant here:
<script>
import {onMount} from "svelte";
const apiURL = "https://jsonplaceholder.typicode.com/todos?_start=1&_limit=20";
let todos = [];
onMount(async function() {
const response = await fetch(apiURL);
todos = await response.json();
todos.reverse();
});
var currentToDo = {};
function editTodo(tid) {
let itemIdx = todos.findIndex(x => x.id == tid);
let currentToDo = todos[itemIdx];
}
<script>
See the REPL here.
The problem is that the text field <input type="text" class="form-control" id="old_todo" value={currentToDo.title} placeholder="Edit Todo">
displays undefined
instead of the current (do be edited) todo title.
Where is my mistake?
Well, currentToDo.title
really is undefined
...
You can change to currentToDo.title || ''
if you want to avoid this display:
<input type="text" class="form-control" id="old_todo" value={currentToDo.title || ''} placeholder="Edit Todo">
Also, to make you Edit button work...
Change this:
<button on:click="{editTodo(t.id)}" class="btn btn-sm btn-primary">Edit</button>
to this:
<button on:click="{() => editTodo(t.id)}" class="btn btn-sm btn-primary">Edit</button>
on:click="{editTodo(t.id)}
becomes on:click="{() => editTodo(t.id)}
, otherwise your editTodo
function is called once per render, but not when the button is actually clicked (in Svelte you pass a function reference, not a function body like normal HTML onclick
for example).
Also, in your editTodo
function:
function editTodo(tid){
let itemIdx = todos.findIndex(x => x.id == tid);
let currentToDo = todos[itemIdx];
}
You need to remove this let
to use the root scope currentToDo
, instead of a locally scoped variable:
function editTodo(tid){
let itemIdx = todos.findIndex(x => x.id == tid);
currentToDo = todos[itemIdx];
}
Then you can click on an Edit button and the title will be displayed in the input field as expected!