You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The `form` function makes it easy to write data to the server. It takes a callback that receives `data` constructed from the submitted [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData)...
The form object contains `method` and `action` properties that allow it to work without JavaScript (i.e. it submits data and reloads the page). It also has an [attachment](/docs/svelte/@attach) that progressively enhances the form when JavaScript is available, submitting data *without* reloading the entire page.
304
+
305
+
As with `query`, if the callback uses the submitted `data`, it should be [validated](#query-Query-arguments) by passing a [Standard Schema](https://standardschema.dev) as the first argument to `form`.
306
+
307
+
### Fields
308
+
309
+
A form is composed of a set of _fields_, which are defined by the schema. In the case of `createPost`, we have two fields, `title` and `content`, which are both strings. To get the attributes for a field, call its `.as(...)` method, specifying which [input type](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input#input_types) to use:
As with `query`, if the callback uses the submitted `data`, it should be [validated](#query-Query-arguments) by passing a [Standard Schema](https://standardschema.dev) as the first argument to `form`. The one difference is to `query` is that the schema inputs must all be of type `string` or `File`, since that's all the original `FormData` provides. You can however coerce the value into a different type — how to do that depends on the validation library you use.
327
+
These attributes allow SvelteKit to set the correct input type, set a `name` that is used to construct the `data` passed to the handler, populate the `value` of the form (for example following a failed submission, to save the user having to re-enter everything), and set the [`aria-invalid`](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Attributes/aria-invalid) state.
313
328
314
-
```ts
315
-
/// file: src/routes/count.remote.js
329
+
Fields can be nested in objects and arrays, and their values can be strings, numbers, booleans or `File` objects. For example, if your schema looked like this...
The `name` attributes on the form controls must correspond to the properties of the schema — `title` and `content` in this case. If you schema contains objects, use object notation:
<input {...info.likesDogs.as('checkbox')} />I like dogs
373
+
</label>
374
+
375
+
<h2>My best attributes</h2>
376
+
<input {...attributes[0].as('text')} />
377
+
<input {...attributes[1].as('text')} />
378
+
<input {...attributes[2].as('text')} />
379
+
380
+
<button>submit</button>
381
+
</form>
349
382
```
350
383
351
-
To indicate a repeated field, use a `[]` suffix:
384
+
Because our form contains a `file` input, we've added an `enctype="multipart/form-data"` attribute. The values for `info.height` and `info.likesDogs` are coerced to a number and a boolean respectively.
385
+
386
+
> [!NOTE] If a `checkbox` input is unchecked, the value is not included in the [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData) object that SvelteKit constructs the data from. As such, we have to make the value optional in our schema. In Valibot that means using `v.optional(v.boolean(), false)` instead of just `v.boolean()`, whereas in Zod it would mean using `z.coerce.boolean<boolean>()`.
387
+
388
+
In the case of `radio` and `checkbox` inputs that all belong to the same field, the `value` must be specified as a second argument to `.as(...)`:
The form object contains `method` and `action` properties that allow it to work without JavaScript (i.e. it submits data and reloads the page). It also has an [attachment](/docs/svelte/@attach) that progressively enhances the form when JavaScript is available, submitting data *without* reloading the entire page.
> [!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(...)`.
371
453
372
454
### Validation
373
455
374
-
If the submitted data doesn't pass the schema, the callback will not run. Instead, the form object's `issues` object will be populated:
456
+
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`:
375
457
376
458
```svelte
377
459
<form {...createPost}>
378
460
<label>
379
461
<h2>Title</h2>
380
462
381
-
+++ {#ifcreatePost.issues.title}
382
-
{#each createPost.issues.title as issue}
383
-
<p class="issue">{issue.message}</p>
384
-
{/each}
385
-
{/if}+++
463
+
+++ {#each createPost.fields.title.issues() as issue}
464
+
<p class="issue">{issue.message}</p>
465
+
{/each}+++
386
466
387
-
<input
388
-
name="title"
389
-
+++aria-invalid={!!createPost.issues.title}+++
390
-
/>
467
+
<input {...createPost.fields.title.as('text')} />
391
468
</label>
392
469
393
470
<label>
394
471
<h2>Write your post</h2>
395
472
396
-
+++ {#ifcreatePost.issues.content}
397
-
{#each createPost.issues.content as issue}
398
-
<p class="issue">{issue.message}</p>
399
-
{/each}
400
-
{/if}+++
473
+
+++ {#each createPost.fields.content.issues() as issue}
@@ -419,7 +491,7 @@ You don't need to wait until the form is submitted to validate the data — you
419
491
420
492
By default, issues will be ignored if they belong to form controls that haven't yet been interacted with. To validate _all_ inputs, call `validate({ includeUntouched:true })`.
421
493
422
-
For client-side validation, you can specify a _preflight_ schema which will populate `issues` and prevent data being sent to the server if the data doesn't validate:
494
+
For client-side validation, you can specify a _preflight_ schema which will populate `issues()` and prevent data being sent to the server if the data doesn't validate:
423
495
424
496
```svelte
425
497
<script>
@@ -441,45 +513,65 @@ For client-side validation, you can specify a _preflight_ schema which will popu
441
513
442
514
> [!NOTE] The preflight schema can be the same object as your server-side schema, if appropriate, though it won't be able to do server-side checks like 'this value already exists in the database'. Note that you cannot export a schema from a `.remote.ts` or `.remote.js` file, so the schema must either be exported from a shared module, or from a `<script module>` block in the component containing the `<form>`.
443
515
444
-
### Live inputs
516
+
To get a list of _all_ issues, rather than just those belonging to a single field, you can use the `fields.allIssues()` method:
445
517
446
-
The form object contains a `input` property which reflects its current value. As the user interacts with the form, `input` is automatically updated:
518
+
```svelte
519
+
{#each createPost.fields.allIssues() as issue}
520
+
<p>{issue.message}</p>
521
+
{/each}
522
+
```
523
+
524
+
### Getting/setting inputs
525
+
526
+
Each field has a `value()` method that reflects its current value. As the user interacts with the form, it is automatically updated:
Alternatively, `createPost.fields.value()` would return a `{ title, content }` object.
540
+
541
+
You can update a field (or a collection of fields) via the `set(...)` method:
542
+
543
+
```svelte
544
+
<script>
545
+
import { createPost } from'../data.remote';
546
+
547
+
// this...
548
+
createPost.fields.set({
549
+
title:'My new blog post',
550
+
content:'Lorem ipsum dolor sit amet...'
551
+
});
552
+
553
+
// ...is equivalent to this:
554
+
createPost.fields.title.set('My new blog post');
555
+
createPost.fields.content.set('Lorem ipsum dolor sit amet');
556
+
</script>
557
+
```
558
+
459
559
### Handling sensitive data
460
560
461
-
In the case of a non-progressively-enhanced form submission (i.e. where JavaScript is unavailable, for whatever reason) `input` is also populated if the submitted data is invalid, so that the user does not need to fill the entire form out from scratch.
561
+
In the case of a non-progressively-enhanced form submission (i.e. where JavaScript is unavailable, for whatever reason) `value()` is also populated if the submitted data is invalid, so that the user does not need to fill the entire form out from scratch.
462
562
463
563
You can prevent sensitive data (such as passwords and credit card numbers) from being sent back to the user by using a name with a leading underscore:
Note that some properties of `RequestEvent` are different inside remote functions. There are no `params` or `route.id`, and you cannot set headers (other than writing cookies, and then only inside `form` and `command` functions), and `url.pathname` is always `/` (since the path that’s actually being requested by the client is purely an implementation detail).
1098
+
Note that some properties of `RequestEvent` are different inside remote functions:
1099
+
1100
+
- you cannot set headers (other than writing cookies, and then only inside `form` and `command` functions)
1101
+
- `route`, `params` and `url` relate to the page the remote function was called from, _not_ the URL of the endpoint SvelteKit creates for the remote function. Queries are not re-run when the user navigates (unless the argument to the query changes as a result of navigation), and so you should be mindful of how you use these values. In particular, never use them to determine whether or not a user is authorized to access certain data.
0 commit comments