Skip to content

Commit 54306fd

Browse files
committed
Add multiple forms test
1 parent 46328cc commit 54306fd

File tree

6 files changed

+146
-3
lines changed

6 files changed

+146
-3
lines changed

src/lib/client/superForm.ts

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/* eslint-disable dci-lint/atomic-role-binding */
22
import type { TaintedFields, SuperFormValidated, SuperValidated } from '$lib/superValidate.js';
3-
import type { ActionResult, Page, SubmitFunction } from '@sveltejs/kit';
3+
import type { ActionResult, BeforeNavigate, Page, SubmitFunction } from '@sveltejs/kit';
44
import {
55
derived,
66
get,
@@ -383,6 +383,28 @@ try {
383383
// No Storybook
384384
}
385385

386+
const onDestroyCallbacks = new Set<() => void>();
387+
const beforeNavigateCallbacks = new Set<(nav: BeforeNavigate) => Promise<void>>();
388+
let lifeCycleHandlersInited = false;
389+
function initLifeCycleCallbacks() {
390+
if (lifeCycleHandlersInited) return;
391+
lifeCycleHandlersInited = true;
392+
393+
onDestroy(() => {
394+
for (const callback of onDestroyCallbacks) {
395+
callback();
396+
}
397+
onDestroyCallbacks.clear();
398+
});
399+
400+
beforeNavigate((nav: BeforeNavigate) => {
401+
for (const callback of beforeNavigateCallbacks) {
402+
callback(nav);
403+
}
404+
beforeNavigateCallbacks.clear();
405+
});
406+
}
407+
386408
/////////////////////////////////////////////////////////////////////
387409

388410
/**
@@ -404,6 +426,8 @@ export function superForm<
404426
// To check if a full validator is used when switching options.validators dynamically
405427
let initialValidator: FormOptions<T, M, In>['validators'] | undefined = undefined;
406428

429+
initLifeCycleCallbacks();
430+
407431
{
408432
if (options.legacy ?? LEGACY_MODE) {
409433
if (options.resetForm === undefined) options.resetForm = false;
@@ -518,7 +542,7 @@ export function superForm<
518542

519543
///// From here, form is properly initialized /////
520544

521-
onDestroy(() => {
545+
onDestroyCallbacks.add(() => {
522546
Unsubscriptions_unsubscribe();
523547
NextChange_clear();
524548
EnhancedForm_destroy();
@@ -1350,7 +1374,7 @@ export function superForm<
13501374
// Tainted check
13511375
const defaultMessage = 'Leave page? Changes that you made may not be saved.';
13521376
let forceRedirection = false;
1353-
beforeNavigate(async (nav) => {
1377+
beforeNavigateCallbacks.add(async (nav: BeforeNavigate) => {
13541378
if (options.taintedMessage && !Data.submitting && !forceRedirection) {
13551379
if (Tainted_isTainted()) {
13561380
const { taintedMessage } = options;

src/routes/(v2)/v2/Navigation.svelte

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
'issue-337-checkboxes',
1515
'issue-345',
1616
'letters',
17+
'multiple-forms',
1718
'multiple-files',
1819
'multistep-client',
1920
'multistep-server',
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { zod } from '$lib/adapters/zod.js';
2+
import { message, superValidate } from '$lib/server/index.js';
3+
import { type Actions, fail } from '@sveltejs/kit';
4+
import { schema } from './schema.js';
5+
6+
const items = [
7+
{
8+
id: 1,
9+
label: 'One'
10+
},
11+
{
12+
id: 2,
13+
label: 'Two'
14+
},
15+
{
16+
id: 3,
17+
label: 'Three'
18+
}
19+
];
20+
21+
export const load = async () => {
22+
const item_forms = await Promise.all(
23+
items.map((item) =>
24+
superValidate(item, zod(schema), {
25+
id: item.id.toString()
26+
})
27+
)
28+
);
29+
30+
return { item_forms };
31+
};
32+
33+
export const actions: Actions = {
34+
async create() {
35+
items.push({
36+
id: items.length + 1,
37+
label: (items.length + 1).toString()
38+
});
39+
40+
return { success: true };
41+
},
42+
43+
async save({ request }) {
44+
const form = await superValidate(request, zod(schema));
45+
46+
if (!form.valid) {
47+
// Again, return { form } and things will just work.
48+
return fail(400, { form });
49+
}
50+
51+
const index = items.findIndex((item) => item.id === form.data.id);
52+
if(index !== -1) {
53+
items[index].label = form.data.label;
54+
}
55+
56+
return message(form, `Item ${form.data.id} updated`);
57+
}
58+
};
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<script lang="ts">
2+
import type { PageData } from './$types.js';
3+
import { superForm } from '$lib/client/index.js';
4+
import Form from './Form.svelte';
5+
import { enhance } from '$app/forms';
6+
7+
let {
8+
data
9+
}: {
10+
data: PageData;
11+
} = $props();
12+
13+
const superforms = $derived(data.item_forms.map(item_form => superForm(item_form, {
14+
id: item_form.id,
15+
dataType: 'json'
16+
})));
17+
</script>
18+
19+
{#each superforms as superform (superform.formId)}
20+
<Form {superform} />
21+
<hr>
22+
{/each}
23+
24+
<form action="?/create" method=post use:enhance>
25+
<button type=submit>Add</button>
26+
</form>
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<script lang="ts">
2+
import type { SuperForm } from '$lib/index.js';
3+
import type { schema } from './schema.js';
4+
import { z } from 'zod';
5+
import SuperDebug from '$lib/client/SuperDebug.svelte';
6+
7+
let { superform }: {
8+
superform: SuperForm<z.infer<typeof schema>>;
9+
} = $props();
10+
11+
let { form, message, enhance } = superform;
12+
</script>
13+
14+
<form action="?/save" method="post" use:enhance>
15+
<input type="hidden" name="id" value={$form.id} />
16+
17+
<SuperDebug data={$form} />
18+
19+
<label>
20+
<input type="text" name="label" bind:value={$form.label} />
21+
</label>
22+
23+
<button type="submit">Save</button>
24+
25+
{#if $message}
26+
<p>{$message}</p>
27+
{/if}
28+
</form>
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { z } from 'zod';
2+
3+
export const schema = z.object({
4+
id: z.number(),
5+
label: z.string()
6+
});

0 commit comments

Comments
 (0)