Skip to content

Commit

Permalink
set form to null before updating it with real values (#9267)
Browse files Browse the repository at this point in the history
* set `form` to `null` before updating it with real values - fixes #8513

* changeset and test
  • Loading branch information
Rich-Harris authored Mar 2, 2023
1 parent 7c8dbf3 commit 744dc81
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 10 deletions.
5 changes: 5 additions & 0 deletions .changeset/thin-readers-speak.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': patch
---

fix: preserve form state when submitting a second time
15 changes: 10 additions & 5 deletions packages/kit/src/runtime/client/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -1410,14 +1410,19 @@ export function create_client(app, target) {
goto(result.location, { invalidateAll: true }, []);
} else {
/** @type {Record<string, any>} */
const props = {
form: result.data,
root.$set({
// this brings Svelte's view of the world in line with SvelteKit's
// after use:enhance reset the form....
form: null,
page: { ...page, form: result.data, status: result.status }
};
root.$set(props);
});

// ...so that setting the `form` prop takes effect and isn't ignored
await tick();
root.$set({ form: result.data });

if (result.type === 'success') {
tick().then(reset_focus);
reset_focus();
}
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,5 +32,12 @@ export const actions = {
},
error: () => {
throw error(400, 'error');
},
echo: async ({ request }) => {
const data = await request.formData();

return {
message: data.get('message')
};
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@
<pre class="formdata2">{JSON.stringify($page.form)}</pre>

<form method="post" action="?/login" use:enhance>
<input type=hidden name="action" value="DOM clobbering" />
<input type=hidden name="reset" value="DOM clobbering" />
<input type="hidden" name="action" value="DOM clobbering" />
<input type="hidden" name="reset" value="DOM clobbering" />
<input name="username" type="text" />
<button class="form1">Submit</button>
<button class="form1-register" formAction="?/register">Submit</button>
<button class="form1-submitter" formAction="?/submitter" name="submitter" value="foo">Submit</button>
<button class="form1-submitter" formAction="?/submitter" name="submitter" value="foo">
Submit
</button>
<button class="form1-error" formAction="?/error">Submit</button>
</form>

Expand All @@ -35,3 +37,8 @@
>
<button class="form2">Submit</button>
</form>

<form method="post" action="?/echo" use:enhance>
<input name="message" type="text" value={form?.message ?? ''} />
<button class="form3">Submit</button>
</form>
19 changes: 17 additions & 2 deletions packages/kit/test/apps/basics/test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -976,7 +976,7 @@ test.describe('Actions', () => {
}
});

test('use:enhance button with formAction', async ({ page, app }) => {
test('use:enhance button with formAction', async ({ page }) => {
await page.goto('/actions/enhance');

expect(await page.textContent('pre.formdata1')).toBe(JSON.stringify(null));
Expand All @@ -989,7 +989,7 @@ test.describe('Actions', () => {
);
});

test('use:enhance button with name', async ({ page, app }) => {
test('use:enhance button with name', async ({ page }) => {
await page.goto('/actions/enhance');

expect(await page.textContent('pre.formdata1')).toBe(JSON.stringify(null));
Expand All @@ -1004,6 +1004,21 @@ test.describe('Actions', () => {
);
});

test('use:enhance does not clear form on second submit', async ({ page }) => {
await page.goto('/actions/enhance');

await page.locator('input[name="message"]').fill('hello');

await page.locator('.form3').click();
await expect(page.locator('pre.formdata1')).toHaveText(JSON.stringify({ message: 'hello' }));
await expect(page.locator('pre.formdata2')).toHaveText(JSON.stringify({ message: 'hello' }));

await page.locator('.form3').click();
await page.waitForTimeout(0); // wait for next tick
await expect(page.locator('pre.formdata1')).toHaveText(JSON.stringify({ message: 'hello' }));
await expect(page.locator('pre.formdata2')).toHaveText(JSON.stringify({ message: 'hello' }));
});

test('redirect', async ({ page, javaScriptEnabled }) => {
await page.goto('/actions/redirect');

Expand Down

0 comments on commit 744dc81

Please sign in to comment.