diff --git a/.changeset/easy-plants-remain.md b/.changeset/easy-plants-remain.md new file mode 100644 index 000000000000..10af2d624bfa --- /dev/null +++ b/.changeset/easy-plants-remain.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +fix: ensure `form` remote functions' `fields.set` triggers reactivity diff --git a/packages/kit/src/runtime/client/remote-functions/form.svelte.js b/packages/kit/src/runtime/client/remote-functions/form.svelte.js index 62c97b2f48d2..2799a397f88a 100644 --- a/packages/kit/src/runtime/client/remote-functions/form.svelte.js +++ b/packages/kit/src/runtime/client/remote-functions/form.svelte.js @@ -537,8 +537,21 @@ export function form(id) { (path, value) => { if (path.length === 0) { input = value; + update_all_versions(); } else { input = deep_set(input, path.map(String), value); + + const key = build_path_string(path); + versions[key] ??= 0; + versions[key] += 1; + touched[key] = true; + + const parent_path = path.slice(); + while (parent_path.pop() !== undefined) { + const parent_key = build_path_string(parent_path); + versions[parent_key] ??= 0; + versions[parent_key] += 1; + } } }, () => issues diff --git a/packages/kit/test/apps/basics/src/routes/remote/form/imperative/+page.svelte b/packages/kit/test/apps/basics/src/routes/remote/form/imperative/+page.svelte new file mode 100644 index 000000000000..c21e4d146af3 --- /dev/null +++ b/packages/kit/test/apps/basics/src/routes/remote/form/imperative/+page.svelte @@ -0,0 +1,35 @@ + + +
+ + +

+ {set_message.fields.message.issues()?.[0]?.message ?? 'ok'} +

+

{set_message.fields.message.value()}

+ + + +
diff --git a/packages/kit/test/apps/basics/test/client.test.js b/packages/kit/test/apps/basics/test/client.test.js index fec98e4a214e..3a4d795fab7b 100644 --- a/packages/kit/test/apps/basics/test/client.test.js +++ b/packages/kit/test/apps/basics/test/client.test.js @@ -1965,6 +1965,18 @@ test.describe('remote functions', () => { await expect(page.locator('p')).toHaveText('success'); }); + test('fields.set updates DOM before validate', async ({ page }) => { + await page.goto('/remote/form/imperative'); + + const input = page.locator('input[name="message"]'); + await input.fill('123'); + + await page.locator('#set-and-validate').click(); + + await expect(input).toHaveValue('hello'); + await expect(page.locator('#issue')).toHaveText('ok'); + }); + test('command pending state is tracked correctly', async ({ page }) => { await page.goto('/remote');