From d3fce037aec7fac9e7cba3be7df4e9f792c8dfb6 Mon Sep 17 00:00:00 2001 From: Dr Use Date: Thu, 9 Apr 2026 22:47:10 +0200 Subject: [PATCH 1/7] fix: make form fields.value() reflect input_value passed to .as() --- .changeset/chatty-bugs-pump.md | 5 ++ .../kit/src/runtime/app/server/remote/form.js | 6 +- .../client/remote-functions/form.svelte.js | 6 +- packages/kit/src/runtime/form-utils.js | 69 ++++++++++++++++--- .../remote/form/value-default/+page.svelte | 11 +++ .../remote/form/value-default/form.remote.ts | 4 ++ .../kit/test/apps/async/test/client.test.js | 13 ++++ 7 files changed, 101 insertions(+), 13 deletions(-) create mode 100644 .changeset/chatty-bugs-pump.md create mode 100644 packages/kit/test/apps/async/src/routes/remote/form/value-default/+page.svelte create mode 100644 packages/kit/test/apps/async/src/routes/remote/form/value-default/form.remote.ts diff --git a/.changeset/chatty-bugs-pump.md b/.changeset/chatty-bugs-pump.md new file mode 100644 index 000000000000..22581ac5b301 --- /dev/null +++ b/.changeset/chatty-bugs-pump.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': major +--- + +fix fields.value() returning undefined when input_value is passed to .as() diff --git a/packages/kit/src/runtime/app/server/remote/form.js b/packages/kit/src/runtime/app/server/remote/form.js index 1e9c8f012872..02ede3991a5d 100644 --- a/packages/kit/src/runtime/app/server/remote/form.js +++ b/packages/kit/src/runtime/app/server/remote/form.js @@ -174,6 +174,8 @@ export function form(validate_or_fn, maybe_fn) { enumerable: true }); + const field_defaults = {}; + Object.defineProperty(instance, 'fields', { get() { return create_field_proxy( @@ -197,7 +199,9 @@ export function form(validate_or_fn, maybe_fn) { deep_set(input, path.map(String), value); (cache[''] ??= { serialize: true, data: {} }).data.input = input; }, - () => flatten_issues(get_cache(__)?.['']?.data?.issues ?? []) + () => flatten_issues(get_cache(__)?.['']?.data?.issues ?? []), + [], + field_defaults ); } }); 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 1af3bffdcc6a..603696a526d3 100644 --- a/packages/kit/src/runtime/client/remote-functions/form.svelte.js +++ b/packages/kit/src/runtime/client/remote-functions/form.svelte.js @@ -489,6 +489,8 @@ export function form(id) { }); } + const field_defaults = {}; + Object.defineProperties(instance, { fields: { get: () => @@ -505,7 +507,9 @@ export function form(id) { touched[key] = true; } }, - () => issues + () => issues, + [], + field_defaults ) }, result: { diff --git a/packages/kit/src/runtime/form-utils.js b/packages/kit/src/runtime/form-utils.js index 72b9cb84abb5..0b0621743c81 100644 --- a/packages/kit/src/runtime/form-utils.js +++ b/packages/kit/src/runtime/form-utils.js @@ -606,11 +606,22 @@ export function deep_get(object, path) { * @param {(path: (string | number)[], value: any) => void} set_input - Function to set input data * @param {() => Record} get_issues - Function to get current issues * @param {(string | number)[]} path - Current access path + * @param {Record} defaults - Default values for fields * @returns {any} Proxy object with name(), value(), and issues() methods */ -export function create_field_proxy(target, get_input, set_input, get_issues, path = []) { +export function create_field_proxy( + target, + get_input, + set_input, + get_issues, + path = [], + defaults = {} +) { const get_value = () => { - return deep_get(get_input(), path); + const from_state = deep_get(get_input(), path); + if (from_state !== undefined) return from_state; + const key = build_path_string(path); + return key in defaults ? defaults[key] : undefined; }; return new Proxy(target, { @@ -619,10 +630,14 @@ export function create_field_proxy(target, get_input, set_input, get_issues, pat // Handle array access like jobs[0] if (/^\d+$/.test(prop)) { - return create_field_proxy({}, get_input, set_input, get_issues, [ - ...path, - parseInt(prop, 10) - ]); + return create_field_proxy( + {}, + get_input, + set_input, + get_issues, + [...path, parseInt(prop, 10)], + defaults + ); } const key = build_path_string(path); @@ -632,11 +647,25 @@ export function create_field_proxy(target, get_input, set_input, get_issues, pat set_input(path, newValue); return newValue; }; - return create_field_proxy(set_func, get_input, set_input, get_issues, [...path, prop]); + return create_field_proxy( + set_func, + get_input, + set_input, + get_issues, + [...path, prop], + defaults + ); } if (prop === 'value') { - return create_field_proxy(get_value, get_input, set_input, get_issues, [...path, prop]); + return create_field_proxy( + get_value, + get_input, + set_input, + get_issues, + [...path, prop], + defaults + ); } if (prop === 'issues' || prop === 'allIssues') { @@ -658,7 +687,14 @@ export function create_field_proxy(target, get_input, set_input, get_issues, pat })); }; - return create_field_proxy(issues_func, get_input, set_input, get_issues, [...path, prop]); + return create_field_proxy( + issues_func, + get_input, + set_input, + get_issues, + [...path, prop], + defaults + ); } if (prop === 'as') { @@ -679,6 +715,10 @@ export function create_field_proxy(target, get_input, set_input, get_issues, pat ? 'b:' : ''; + if (input_value !== undefined) { + defaults[key] = input_value; + } + // Base properties for all input types /** @type {Record} */ const base_props = { @@ -807,11 +847,18 @@ export function create_field_proxy(target, get_input, set_input, get_issues, pat }); }; - return create_field_proxy(as_func, get_input, set_input, get_issues, [...path, 'as']); + return create_field_proxy( + as_func, + get_input, + set_input, + get_issues, + [...path, 'as'], + defaults + ); } // Handle property access (nested fields) - return create_field_proxy({}, get_input, set_input, get_issues, [...path, prop]); + return create_field_proxy({}, get_input, set_input, get_issues, [...path, prop], defaults); } }); } diff --git a/packages/kit/test/apps/async/src/routes/remote/form/value-default/+page.svelte b/packages/kit/test/apps/async/src/routes/remote/form/value-default/+page.svelte new file mode 100644 index 000000000000..69067c440c08 --- /dev/null +++ b/packages/kit/test/apps/async/src/routes/remote/form/value-default/+page.svelte @@ -0,0 +1,11 @@ + + +
+ +

{test_form.fields.name.value()}

+
diff --git a/packages/kit/test/apps/async/src/routes/remote/form/value-default/form.remote.ts b/packages/kit/test/apps/async/src/routes/remote/form/value-default/form.remote.ts new file mode 100644 index 000000000000..999468eb5f56 --- /dev/null +++ b/packages/kit/test/apps/async/src/routes/remote/form/value-default/form.remote.ts @@ -0,0 +1,4 @@ +import { form } from '$app/server'; +import * as v from 'valibot'; + +export const test_form = form(v.object({ name: v.string() }), async (data) => {}); diff --git a/packages/kit/test/apps/async/test/client.test.js b/packages/kit/test/apps/async/test/client.test.js index 1f02d02d2f0d..c93b084c160c 100644 --- a/packages/kit/test/apps/async/test/client.test.js +++ b/packages/kit/test/apps/async/test/client.test.js @@ -484,6 +484,19 @@ test.describe('remote function mutations', () => { } }); + test('.value() reflects input_value default before any user interaction', async ({ page }) => { + await page.goto('/remote/form/value-default'); + + const input = page.locator('[data-testid="as-value-default-input"]'); + const display = page.locator('#default-value-display'); + + // l'input doit afficher la valeur par défaut + await expect(input).toHaveValue('default text'); + + // value() doit aussi retourner la valeur par défaut SANS interaction préalable + await expect(display).toHaveText('default text'); + }); + test('.as(type, value) updates when data changes after submission', async ({ page }) => { await page.goto('/remote/form/as-value'); From 20514d352e58c3b7632ec9838220aee0816f64e3 Mon Sep 17 00:00:00 2001 From: MATAAM Mohamed <47464474+DrUse1@users.noreply.github.com> Date: Thu, 9 Apr 2026 23:12:38 +0200 Subject: [PATCH 2/7] Change changelog from major to patch --- .changeset/chatty-bugs-pump.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/chatty-bugs-pump.md b/.changeset/chatty-bugs-pump.md index 22581ac5b301..3f5fc15611dc 100644 --- a/.changeset/chatty-bugs-pump.md +++ b/.changeset/chatty-bugs-pump.md @@ -1,5 +1,5 @@ --- -'@sveltejs/kit': major +'@sveltejs/kit': patch --- fix fields.value() returning undefined when input_value is passed to .as() From 3be77bd6edd9b4bbdfa62983d593133fa538c9de Mon Sep 17 00:00:00 2001 From: MATAAM Mohamed <47464474+DrUse1@users.noreply.github.com> Date: Sat, 11 Apr 2026 14:32:12 +0200 Subject: [PATCH 3/7] chore: trigger CI/CD --- .changeset/chatty-bugs-pump.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/chatty-bugs-pump.md b/.changeset/chatty-bugs-pump.md index 3f5fc15611dc..89f2a08b8fe0 100644 --- a/.changeset/chatty-bugs-pump.md +++ b/.changeset/chatty-bugs-pump.md @@ -2,4 +2,4 @@ '@sveltejs/kit': patch --- -fix fields.value() returning undefined when input_value is passed to .as() +fix fields.value() returning undefined when input_value is passed to .as() From ea8158e9b36f842a20259061c3a2e425a672120a Mon Sep 17 00:00:00 2001 From: Dr Use Date: Sun, 12 Apr 2026 19:03:34 +0200 Subject: [PATCH 4/7] translate comments, placing value display before input --- packages/kit/src/runtime/form-utils.js | 2 +- .../async/src/routes/remote/form/value-default/+page.svelte | 2 +- packages/kit/test/apps/async/test/client.test.js | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/kit/src/runtime/form-utils.js b/packages/kit/src/runtime/form-utils.js index 0b0621743c81..4836021bbb24 100644 --- a/packages/kit/src/runtime/form-utils.js +++ b/packages/kit/src/runtime/form-utils.js @@ -615,7 +615,7 @@ export function create_field_proxy( set_input, get_issues, path = [], - defaults = {} + defaults, ) { const get_value = () => { const from_state = deep_get(get_input(), path); diff --git a/packages/kit/test/apps/async/src/routes/remote/form/value-default/+page.svelte b/packages/kit/test/apps/async/src/routes/remote/form/value-default/+page.svelte index 69067c440c08..a809c9e6b5bb 100644 --- a/packages/kit/test/apps/async/src/routes/remote/form/value-default/+page.svelte +++ b/packages/kit/test/apps/async/src/routes/remote/form/value-default/+page.svelte @@ -3,9 +3,9 @@
+

{test_form.fields.name.value()}

-

{test_form.fields.name.value()}

diff --git a/packages/kit/test/apps/async/test/client.test.js b/packages/kit/test/apps/async/test/client.test.js index c93b084c160c..7f2947659064 100644 --- a/packages/kit/test/apps/async/test/client.test.js +++ b/packages/kit/test/apps/async/test/client.test.js @@ -490,10 +490,10 @@ test.describe('remote function mutations', () => { const input = page.locator('[data-testid="as-value-default-input"]'); const display = page.locator('#default-value-display'); - // l'input doit afficher la valeur par défaut + // input has to output the default value provided await expect(input).toHaveValue('default text'); - // value() doit aussi retourner la valeur par défaut SANS interaction préalable + // value() also needs to output the default value provided WITHOUT any user interaction await expect(display).toHaveText('default text'); }); From af043ac2a20b0b92283a69cc119f0393ed5ca614 Mon Sep 17 00:00:00 2001 From: Dr Use Date: Sun, 12 Apr 2026 19:08:10 +0200 Subject: [PATCH 5/7] linting --- packages/kit/src/runtime/form-utils.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/packages/kit/src/runtime/form-utils.js b/packages/kit/src/runtime/form-utils.js index 4836021bbb24..74d4a66dd4e1 100644 --- a/packages/kit/src/runtime/form-utils.js +++ b/packages/kit/src/runtime/form-utils.js @@ -609,14 +609,7 @@ export function deep_get(object, path) { * @param {Record} defaults - Default values for fields * @returns {any} Proxy object with name(), value(), and issues() methods */ -export function create_field_proxy( - target, - get_input, - set_input, - get_issues, - path = [], - defaults, -) { +export function create_field_proxy(target, get_input, set_input, get_issues, path = [], defaults) { const get_value = () => { const from_state = deep_get(get_input(), path); if (from_state !== undefined) return from_state; From 88929960c5cde5948b7674a36c6f93e73e272d8f Mon Sep 17 00:00:00 2001 From: Dr Use Date: Sun, 12 Apr 2026 19:57:44 +0200 Subject: [PATCH 6/7] trying new approach : set_input when default is provided CAREFUL : I needed to change a pre-existing test that was failing --- .../kit/src/runtime/app/server/remote/form.js | 6 +- .../client/remote-functions/form.svelte.js | 6 +- packages/kit/src/runtime/form-utils.js | 67 +++++-------------- .../routes/remote/form/as-value/+page.svelte | 15 +++-- 4 files changed, 28 insertions(+), 66 deletions(-) diff --git a/packages/kit/src/runtime/app/server/remote/form.js b/packages/kit/src/runtime/app/server/remote/form.js index 02ede3991a5d..1e9c8f012872 100644 --- a/packages/kit/src/runtime/app/server/remote/form.js +++ b/packages/kit/src/runtime/app/server/remote/form.js @@ -174,8 +174,6 @@ export function form(validate_or_fn, maybe_fn) { enumerable: true }); - const field_defaults = {}; - Object.defineProperty(instance, 'fields', { get() { return create_field_proxy( @@ -199,9 +197,7 @@ export function form(validate_or_fn, maybe_fn) { deep_set(input, path.map(String), value); (cache[''] ??= { serialize: true, data: {} }).data.input = input; }, - () => flatten_issues(get_cache(__)?.['']?.data?.issues ?? []), - [], - field_defaults + () => flatten_issues(get_cache(__)?.['']?.data?.issues ?? []) ); } }); 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 603696a526d3..1af3bffdcc6a 100644 --- a/packages/kit/src/runtime/client/remote-functions/form.svelte.js +++ b/packages/kit/src/runtime/client/remote-functions/form.svelte.js @@ -489,8 +489,6 @@ export function form(id) { }); } - const field_defaults = {}; - Object.defineProperties(instance, { fields: { get: () => @@ -507,9 +505,7 @@ export function form(id) { touched[key] = true; } }, - () => issues, - [], - field_defaults + () => issues ) }, result: { diff --git a/packages/kit/src/runtime/form-utils.js b/packages/kit/src/runtime/form-utils.js index 74d4a66dd4e1..b7d24eaee62e 100644 --- a/packages/kit/src/runtime/form-utils.js +++ b/packages/kit/src/runtime/form-utils.js @@ -6,6 +6,7 @@ import { DEV } from 'esm-env'; import * as devalue from 'devalue'; import { text_decoder, text_encoder } from './utils.js'; import { SvelteKitError } from '@sveltejs/kit/internal'; +import { untrack } from 'svelte'; /** * Sets a value in a nested object using a path string, mutating the original object @@ -606,15 +607,11 @@ export function deep_get(object, path) { * @param {(path: (string | number)[], value: any) => void} set_input - Function to set input data * @param {() => Record} get_issues - Function to get current issues * @param {(string | number)[]} path - Current access path - * @param {Record} defaults - Default values for fields * @returns {any} Proxy object with name(), value(), and issues() methods */ -export function create_field_proxy(target, get_input, set_input, get_issues, path = [], defaults) { +export function create_field_proxy(target, get_input, set_input, get_issues, path = []) { const get_value = () => { - const from_state = deep_get(get_input(), path); - if (from_state !== undefined) return from_state; - const key = build_path_string(path); - return key in defaults ? defaults[key] : undefined; + return deep_get(get_input(), path); }; return new Proxy(target, { @@ -623,14 +620,10 @@ export function create_field_proxy(target, get_input, set_input, get_issues, pat // Handle array access like jobs[0] if (/^\d+$/.test(prop)) { - return create_field_proxy( - {}, - get_input, - set_input, - get_issues, - [...path, parseInt(prop, 10)], - defaults - ); + return create_field_proxy({}, get_input, set_input, get_issues, [ + ...path, + parseInt(prop, 10) + ]); } const key = build_path_string(path); @@ -640,25 +633,11 @@ export function create_field_proxy(target, get_input, set_input, get_issues, pat set_input(path, newValue); return newValue; }; - return create_field_proxy( - set_func, - get_input, - set_input, - get_issues, - [...path, prop], - defaults - ); + return create_field_proxy(set_func, get_input, set_input, get_issues, [...path, prop]); } if (prop === 'value') { - return create_field_proxy( - get_value, - get_input, - set_input, - get_issues, - [...path, prop], - defaults - ); + return create_field_proxy(get_value, get_input, set_input, get_issues, [...path, prop]); } if (prop === 'issues' || prop === 'allIssues') { @@ -680,14 +659,7 @@ export function create_field_proxy(target, get_input, set_input, get_issues, pat })); }; - return create_field_proxy( - issues_func, - get_input, - set_input, - get_issues, - [...path, prop], - defaults - ); + return create_field_proxy(issues_func, get_input, set_input, get_issues, [...path, prop]); } if (prop === 'as') { @@ -708,8 +680,12 @@ export function create_field_proxy(target, get_input, set_input, get_issues, pat ? 'b:' : ''; - if (input_value !== undefined) { - defaults[key] = input_value; + // if (input_value !== undefined) { + // defaults[key] = input_value; + // } + + if (input_value !== undefined && get_value() == null) { + untrack(() => set_input(path, input_value)); } // Base properties for all input types @@ -840,18 +816,11 @@ export function create_field_proxy(target, get_input, set_input, get_issues, pat }); }; - return create_field_proxy( - as_func, - get_input, - set_input, - get_issues, - [...path, 'as'], - defaults - ); + return create_field_proxy(as_func, get_input, set_input, get_issues, [...path, 'as']); } // Handle property access (nested fields) - return create_field_proxy({}, get_input, set_input, get_issues, [...path, prop], defaults); + return create_field_proxy({}, get_input, set_input, get_issues, [...path, prop]); } }); } diff --git a/packages/kit/test/apps/async/src/routes/remote/form/as-value/+page.svelte b/packages/kit/test/apps/async/src/routes/remote/form/as-value/+page.svelte index dc06e5dcceae..48f8a46ac347 100644 --- a/packages/kit/test/apps/async/src/routes/remote/form/as-value/+page.svelte +++ b/packages/kit/test/apps/async/src/routes/remote/form/as-value/+page.svelte @@ -11,27 +11,28 @@ {/each} {#each values as value (value.id)} + {@const form = as_value_form.for(value.id)}
{ + {...form.enhance(({ submit }) => { // TODO: needed to keep the values when JS is enabled, remove when reset is implemented submit(); })} > - + - + - - + - + - +
{/each} From f28519de13952dbb4adebf2a4386457be811a4df Mon Sep 17 00:00:00 2001 From: Dr Use Date: Sun, 12 Apr 2026 19:58:59 +0200 Subject: [PATCH 7/7] better comment --- packages/kit/src/runtime/form-utils.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/kit/src/runtime/form-utils.js b/packages/kit/src/runtime/form-utils.js index b7d24eaee62e..52fb05d0271c 100644 --- a/packages/kit/src/runtime/form-utils.js +++ b/packages/kit/src/runtime/form-utils.js @@ -680,10 +680,7 @@ export function create_field_proxy(target, get_input, set_input, get_issues, pat ? 'b:' : ''; - // if (input_value !== undefined) { - // defaults[key] = input_value; - // } - + // If the input has a default value and there is no current value, set it to the default value if (input_value !== undefined && get_value() == null) { untrack(() => set_input(path, input_value)); }