Skip to content

Commit 19bc530

Browse files
Sync kit docs (#1593)
sync kit docs Co-authored-by: svelte-docs-bot[bot] <196124396+svelte-docs-bot[bot]@users.noreply.github.com>
1 parent c22df12 commit 19bc530

File tree

3 files changed

+92
-6
lines changed

3 files changed

+92
-6
lines changed

apps/svelte.dev/content/docs/kit/20-core-concepts/60-remote-functions.md

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -451,6 +451,43 @@ Alternatively, you could use `select` and `select multiple`:
451451
452452
> [!NOTE] As with unchecked `checkbox` inputs, if no selections are made then the data will be `undefined`. For this reason, the `languages` field uses `v.optional(v.array(...), [])` rather than just `v.array(...)`.
453453
454+
### Programmatic validation
455+
456+
In addition to declarative schema validation, you can programmatically mark fields as invalid inside the form handler using the `invalid` function. This is useful for cases where you can't know if something is valid until you try to perform some action:
457+
458+
```js
459+
/// file: src/routes/shop/data.remote.js
460+
import * as v from 'valibot';
461+
import { form } from '$app/server';
462+
import * as db from '$lib/server/database';
463+
464+
export const buyHotcakes = form(
465+
v.object({
466+
qty: v.pipe(
467+
v.number(),
468+
v.minValue(1, 'you must buy at least one hotcake')
469+
)
470+
}),
471+
async (data, invalid) => {
472+
try {
473+
await db.buy(data.qty);
474+
} catch (e) {
475+
if (e.code === 'OUT_OF_STOCK') {
476+
invalid(
477+
invalid.qty(`we don't have enough hotcakes`)
478+
);
479+
}
480+
}
481+
}
482+
);
483+
```
484+
485+
The `invalid` function works as both a function and a proxy:
486+
487+
- Call `invalid(issue1, issue2, ...issueN)` to throw a validation error
488+
- If an issue is a `string`, it applies to the form as a whole (and will show up in `fields.allIssues()`)
489+
- Use `invalid.fieldName(message)` to create an issue for a specific field. Like `fields` this is type-safe and you can use regular property access syntax to create issues for deeply nested objects (e.g. `invalid.profile.email('Email already exists')` or `invalid.items[0].qty('Insufficient stock')`)
490+
454491
### Validation
455492
456493
If the submitted data doesn't pass the schema, the callback will not run. Instead, each invalid field's `issues()` method will return an array of `{ message: string }` objects, and the `aria-invalid` attribute (returned from `as(...)`) will be set to `true`:
@@ -756,6 +793,27 @@ await submit().updates(
756793

757794
The override will be applied immediately, and released when the submission completes (or fails).
758795

796+
### Multiple instances of a form
797+
798+
Some forms may be repeated as part of a list. In this case you can create separate instances of a form function via `for(id)` to achieve isolation.
799+
800+
```svelte
801+
<!--- file: src/routes/todos/+page.svelte --->
802+
<script>
803+
import { getTodos, modifyTodo } from '../data.remote';
804+
</script>
805+
806+
<h1>Todos</h1>
807+
808+
{#each await getTodos() as todo}
809+
{@const modify = modifyTodo.for(todo.id)}
810+
<form {...modify}>
811+
<!-- -->
812+
<button disabled={!!modify.pending}>save changes</button>
813+
</form>
814+
{/each}
815+
```
816+
759817
### buttonProps
760818
761819
By default, submitting a form will send a request to the URL indicated by the `<form>` element's [`action`](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/form#attributes_for_form_submission) attribute, which in the case of a remote function is a property on the form object generated by SvelteKit.

apps/svelte.dev/content/docs/kit/98-reference/[email protected]

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1253,6 +1253,26 @@ The content of the error.
12531253
</div>
12541254
</div></div>
12551255

1256+
## Invalid
1257+
1258+
A function and proxy object used to imperatively create validation errors in form handlers.
1259+
1260+
Call `invalid(issue1, issue2, ...issueN)` to throw a validation error.
1261+
If an issue is a `string`, it applies to the form as a whole (and will show up in `fields.allIssues()`)
1262+
Access properties to create field-specific issues: `invalid.fieldName('message')`.
1263+
The type structure mirrors the input data structure for type-safe field access.
1264+
1265+
<div class="ts-block">
1266+
1267+
```dts
1268+
type Invalid<Input = any> = ((
1269+
...issues: Array<string | StandardSchemaV1.Issue>
1270+
) => never) &
1271+
InvalidField<Input>;
1272+
```
1273+
1274+
</div>
1275+
12561276
## KitConfig
12571277

12581278
See the [configuration reference](/docs/kit/configuration) for details.
@@ -2315,8 +2335,8 @@ type RemoteForm<
23152335
[attachment: symbol]: (node: HTMLFormElement) => void;
23162336
};
23172337
/**
2318-
* Create an instance of the form for the given key.
2319-
* The key is stringified and used for deduplication to potentially reuse existing instances.
2338+
* Create an instance of the form for the given `id`.
2339+
* The `id` is stringified and used for deduplication to potentially reuse existing instances.
23202340
* Useful when you have multiple forms that use the same remote form action, for example in a loop.
23212341
* ```svelte
23222342
* {#each todos as todo}
@@ -2329,7 +2349,7 @@ type RemoteForm<
23292349
* ```
23302350
*/
23312351
for(
2332-
key: string | number | boolean
2352+
id: ExtractId<Input>
23332353
): Omit<RemoteForm<Input, Output>, 'for'>;
23342354
/** Preflight checks */
23352355
preflight(

apps/svelte.dev/content/docs/kit/98-reference/20-$app-server.md

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,9 @@ See [Remote functions](/docs/kit/remote-functions#form) for full documentation.
8282

8383
```dts
8484
function form<Output>(
85-
fn: () => MaybePromise<Output>
85+
fn: (
86+
invalid: import('@sveltejs/kit').Invalid<void>
87+
) => MaybePromise<Output>
8688
): RemoteForm<void, Output>;
8789
```
8890

@@ -93,7 +95,10 @@ function form<Output>(
9395
```dts
9496
function form<Input extends RemoteFormInput, Output>(
9597
validate: 'unchecked',
96-
fn: (data: Input) => MaybePromise<Output>
98+
fn: (
99+
data: Input,
100+
invalid: import('@sveltejs/kit').Invalid<Input>
101+
) => MaybePromise<Output>
97102
): RemoteForm<Input, Output>;
98103
```
99104

@@ -111,7 +116,10 @@ function form<
111116
>(
112117
validate: Schema,
113118
fn: (
114-
data: StandardSchemaV1.InferOutput<Schema>
119+
data: StandardSchemaV1.InferOutput<Schema>,
120+
invalid: import('@sveltejs/kit').Invalid<
121+
StandardSchemaV1.InferOutput<Schema>
122+
>
115123
) => MaybePromise<Output>
116124
): RemoteForm<StandardSchemaV1.InferInput<Schema>, Output>;
117125
```

0 commit comments

Comments
 (0)