Skip to content

Commit ce3318a

Browse files
author
Mike Nikles
committed
Enhance HTML forms.
1 parent b0f6d52 commit ce3318a

File tree

4 files changed

+78
-7
lines changed

4 files changed

+78
-7
lines changed

src/lib/actions/form.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
export const enhance = (form: HTMLFormElement, {
2+
result
3+
}) => {
4+
5+
const handleSubmit = async (event: Event) => {
6+
event.preventDefault();
7+
8+
try {
9+
const body = new FormData(form);
10+
const res = await fetch(form.action, {
11+
method: form.method,
12+
headers: {
13+
accept: "application/json"
14+
},
15+
body
16+
});
17+
18+
if (res.ok) {
19+
result(res, form);
20+
} else {
21+
console.error("Fetch error: ", await res.text());
22+
}
23+
} catch (error) {
24+
console.error("Could not submit the form: ", error);
25+
}
26+
};
27+
28+
form.addEventListener("submit", handleSubmit);
29+
30+
return {
31+
destroy() {
32+
form.removeEventListener("submit", handleSubmit);
33+
}
34+
}
35+
};

src/lib/todo-item.svelte

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
<script lang="ts">
2+
import { enhance } from "$lib/actions/form";
3+
24
export let todo: Todo;
5+
export let processDeletedTodoResult: (res: Response) => void;
6+
export let processUpdatedTodoResult: (res: Response) => void;
37
</script>
48

59
<style>
@@ -82,17 +86,23 @@
8286
</style>
8387

8488
<div class="todo" class:done={todo.done}>
85-
<form action="/todos/{todo.uid}.json?_method=patch" method="post">
89+
<form action="/todos/{todo.uid}.json?_method=patch" method="post" use:enhance={{
90+
result: processUpdatedTodoResult
91+
}}>
8692
<input type="hidden" name="done" value="{todo.done ? '' : 'true'}" />
8793
<button aria-label="Mark todo as {todo.done ? 'not done' : 'done'}" class="toggle"></button>
8894
</form>
8995

90-
<form action="/todos/{todo.uid}.json?_method=patch" method="post" class="text">
96+
<form action="/todos/{todo.uid}.json?_method=patch" method="post" class="text" use:enhance={{
97+
result: processUpdatedTodoResult
98+
}}>
9199
<input type="text" name="text" value="{todo.text}" />
92100
<button aria-label="Save todo" class="save"></button>
93101
</form>
94102

95-
<form action="/todos/{todo.uid}.json?_method=delete" method="post">
103+
<form action="/todos/{todo.uid}.json?_method=delete" method="post" use:enhance={{
104+
result: processDeletedTodoResult
105+
}}>
96106
<button aria-label="Delete todo" class="delete"></button>
97107
</form>
98108
</div>

src/routes/index.svelte

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<script context="module" lang="ts">
22
import type { Load } from "@sveltejs/kit";
3+
import { enhance } from "$lib/actions/form";
34
45
export const load: Load = async ({ fetch }) => {
56
const res = await fetch("/todos.json");
@@ -24,6 +25,21 @@
2425
export let todos: Todo[];
2526
2627
const title = "Todo";
28+
29+
const processNewTodoResult = async (res: Response, form: HTMLFormElement) => {
30+
const newTodo = await res.json();
31+
todos = [...todos, newTodo];
32+
33+
form.reset();
34+
};
35+
36+
const processUpdatedTodoResult = async (res: Response) => {
37+
const updatedTodo = await res.json();
38+
todos = todos.map(t => {
39+
if (t.uid === updatedTodo.uid) return updatedTodo;
40+
return t;
41+
})
42+
};
2743
</script>
2844

2945
<style>
@@ -64,12 +80,20 @@
6480

6581
<div class="todos">
6682
<h1>{title}</h1>
67-
68-
<form action="/todos.json" method="post" class="new">
83+
84+
<form action="/todos.json" method="post" class="new" use:enhance={{
85+
result: processNewTodoResult
86+
}}>
6987
<input type="text" name="text" aria-label="Add a todo" placeholder="+ type to add a todo" />
7088
</form>
7189

7290
{#each todos as todo}
73-
<TodoItem {todo} />
91+
<TodoItem
92+
{todo}
93+
processDeletedTodoResult={() => {
94+
todos = todos.filter(t => t.uid !== todo.uid);
95+
}}
96+
{processUpdatedTodoResult}
97+
/>
7498
{/each}
7599
</div>

src/routes/todos/_api.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,15 @@ export const api = (request: Request, data?: Record<string, unknown>) => {
3030
return todo;
3131
});
3232
status = 200;
33+
body = todos.find(todo => todo.uid === request.params.uid);
3334
break;
3435

3536
default:
3637
break;
3738
}
3839

39-
if (request.method.toUpperCase() !== "GET") {
40+
if (request.method.toUpperCase() !== "GET" &&
41+
request.headers.accept !== "application/json") {
4042
return {
4143
status: 303,
4244
headers: {

0 commit comments

Comments
 (0)