CRUD Operations
Adding new tasks
Now that we can see the list of tasks, it's time to add a few more. We create a form which executes the addTask
function that invokes taskRepo.insert()
. Update your +page.svelte
as follows:
<script lang="ts">
import { repo } from "remult";
import { Task } from "../shared/Task";
let tasks = $state<Task[]>([]);
$effect(() => {
repo(Task)
.find()
.then((t) => (tasks = t));
});
let newTaskTitle = $state("");
const addTask = async (event: Event) => {
event.preventDefault();
const newTask = await repo(Task).insert({ title: newTaskTitle });
tasks = [...tasks, newTask];
newTaskTitle = "";
};
</script>
<div>
<h1>todos</h1>
<main>
<form onsubmit={addTask}>
<input bind:value={newTaskTitle} placeholder="What needs to be done?" />
<button>Add</button>
</form>
{#each tasks as task}
<div>
<input type="checkbox" bind:checked={task.completed} />
<span>{task.title}</span>
</div>
{/each}
</main>
</div>
The call to insert
will make a post request to the server, insert the new task to the db, and return the new Task object with all it's info (including the id generated by the database)
Try adding a few tasks to see how it works.
Mark Tasks as Completed
- Add a
setCompleted
function in the script section as follows:
const setCompleted = async (task: Task, completed: boolean) => {
await repo(Task).save({ ...task, completed })
}
- Modify the checkbox to invoke the method:
<div>
<input
type="checkbox"
checked={task.completed}
oninput={(e) => setCompleted(task, e.currentTarget.checked)}
/>
<span>{task.title}</span>
</div>
Rename Tasks
To make the tasks in the list updatable, we'll use an input
element and bind it to the task's title
property. We'll also add a Save button to commit the changes to the backend database.
- Add a
saveTask
function in the script section as follows:
const saveTask = async (e: Event, task: Task) => {
e.preventDefault()
await repo(Task).save({ ...task })
}
- Update the html part
{#each tasks as task}
<div>
<input
type="checkbox"
checked={task.completed}
oninput={(e) => setCompleted(task, e.currentTarget.checked)}
/>
<input name="title" bind:value={task.title} />
<button onclick={(e) => saveTask(e, task)}>Save</button>
</div>
{/each}
The saveTask
function saves the task that is passed in. Since the task's title is bound to the input
, changes are made directly to the task.
Make some changes and refresh the browser to verify that the backend database is updated.
Browser's Network tab
As you play with these CRUD
capabilities, monitor the network tab and see that they are all translated to rest
api calls.
Delete Tasks
Let's add a Delete button next to the Save button of each task in the list.
- Add the
deleteTask
function
const deleteTask = async (e: Event, task: Task) => {
e.preventDefault()
await repo(Task).delete(task)
tasks = tasks.filter((c) => c.id !== task.id)
}
- Add the Delete button
{#each tasks as task}
<div>
<input
type="checkbox"
checked={task.completed}
oninput={(e) => setCompleted(task, e.currentTarget.checked)}
/>
<input name="title" bind:value={task.title} />
<button onclick={(e) => saveTask(e, task)}>Save</button>
<button onclick={(e) => deleteTask(e, task)}>Delete</button>
</div>
{/each}