Skip to content

Commit ebeaf8c

Browse files
committed
Forms in components weren't resetted properly when destroyed and created again.
1 parent 776f012 commit ebeaf8c

File tree

6 files changed

+93
-9
lines changed

6 files changed

+93
-9
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ Headlines: Added, Changed, Deprecated, Removed, Fixed, Security
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [1.5.2] - 2023-08-15
9+
10+
### Fixed
11+
12+
- Forms in components weren't resetted properly when destroyed and created again.
13+
814
## [1.5.1] - 2023-08-09
915

1016
### Fixed

src/lib/client/index.ts

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,9 @@ export type EnhancedForm<T extends AnyZodObject, M = any> = SuperForm<T, M>;
256256

257257
const formIds = new WeakMap<Page, Set<string | undefined>>();
258258

259+
// Track ActionData, so it won't be applied twice for componentized forms.
260+
const postedActionData = new WeakSet<object>();
261+
259262
function multipleFormIdError(id: string | undefined) {
260263
return (
261264
`Duplicate form id's found: "${id}". ` +
@@ -338,13 +341,20 @@ export function superForm<
338341
}
339342
}
340343

344+
// Need to clone the validation data, in case it's used to populate multiple forms.
345+
const initialForm = clone(form);
346+
341347
// Detect if a form is posted without JavaScript.
342348
const postedData = _currentPage.form;
343-
if (postedData && typeof postedData === 'object') {
349+
350+
if (!browser && postedData && typeof postedData === 'object') {
344351
for (const postedForm of Context_findValidationForms(
345352
postedData
346353
).reverse()) {
347-
if (postedForm.id === _formId) {
354+
if (postedForm.id === _formId && !postedActionData.has(postedForm)) {
355+
// Prevent multiple "posting" that can happen when components are recreated.
356+
postedActionData.add(postedData);
357+
348358
const pageDataForm = form as SuperValidated<T, M>;
349359
form = postedForm as SuperValidated<T, M>;
350360
// Reset the form if option set and form is valid.
@@ -363,13 +373,10 @@ export function superForm<
363373

364374
const form2 = form as SuperValidated<T, M>;
365375

366-
// Need to clone the validation data, in case it's used to populate multiple forms.
367-
const initialForm = clone(form2);
368-
369376
if (typeof initialForm.valid !== 'boolean') {
370377
throw new SuperFormError(
371378
'A non-validation object was passed to superForm. ' +
372-
"Check what's passed to its first parameter."
379+
'It should be an object of type SuperValidated, usually returned from superValidate.'
373380
);
374381
}
375382

@@ -818,13 +825,20 @@ export function superForm<
818825
const untaint = pageUpdate.status >= 200 && pageUpdate.status < 300;
819826

820827
if (pageUpdate.form && typeof pageUpdate.form === 'object') {
828+
const actionData = pageUpdate.form;
829+
821830
// Check if it is an error result, sent here from formEnhance
822-
if (pageUpdate.form.type == 'error') return;
831+
if (actionData.type == 'error') return;
823832

824-
const forms = Context_findValidationForms(pageUpdate.form);
833+
const forms = Context_findValidationForms(actionData);
825834
for (const newForm of forms) {
826835
//console.log('🚀~ ActionData ~ newForm:', newForm.id);
827-
if (newForm.id !== _formId) continue;
836+
if (newForm.id !== _formId || postedActionData.has(newForm)) {
837+
continue;
838+
}
839+
840+
// Prevent multiple "posting" that can happen when components are recreated.
841+
postedActionData.add(newForm);
828842

829843
await Form_updateFromValidation(
830844
newForm as SuperValidated<T, M>,
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<script>
2+
import Form from './Form.svelte';
3+
4+
let formVisible = true;
5+
</script>
6+
7+
<button on:click={() => (formVisible = !formVisible)}
8+
>toggle form visibility</button
9+
>
10+
11+
<h1>Main page</h1>
12+
13+
{#if formVisible}
14+
<Form />
15+
{/if}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const ssr = false;
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<script>
2+
import { superForm, superValidateSync } from '$lib/client';
3+
import { z } from 'zod';
4+
import { onDestroy } from 'svelte';
5+
import SuperDebug from '$lib/client/SuperDebug.svelte';
6+
import { page } from '$app/stores';
7+
import { get } from 'svelte/store';
8+
9+
const schema = z.object({
10+
id: z.number().min(1).max(255).default(1),
11+
name: z
12+
.string()
13+
.min(1, 'Name must contain at least 1 character')
14+
.max(255, 'Name must not exceed 255 characters')
15+
.default('')
16+
});
17+
18+
const data = superValidateSync(schema);
19+
20+
const { form, errors, enhance, constraints, reset } = superForm(data, {
21+
SPA: true,
22+
validators: schema,
23+
taintedMessage: null,
24+
25+
onUpdate({ form }) {
26+
if (form.valid) {
27+
console.log('form is valid', form.data);
28+
// TODO: Do something with the validated form.data
29+
}
30+
}
31+
});
32+
</script>
33+
34+
<form method="POST" class="flex flex-col h-[300px] gap-4" use:enhance>
35+
<input bind:value={$form.id} {...$constraints.id} />
36+
<input bind:value={$form.name} {...$constraints.name} />
37+
38+
<button type="submit"> submit</button>
39+
</form>
40+
41+
<br />
42+
43+
<SuperDebug data={{ $form, $errors, 'page.form': $page.form?.form }} />
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { z } from 'zod';
2+
3+
export const schema = z.object({
4+
name: z.string().min(1)
5+
});

0 commit comments

Comments
 (0)