chainlist / Svelte Forms
Programming Languages
Labels
Projects that are alternatives of or similar to Svelte Forms
Svelte Forms Validation
Install
npm i -D svelte-forms
or
yarn add -D svelte-forms
Update notes
As of version 1.1.0, the field validation objects are no longer directly located inside of the form validation object but rather in a sub-property of it (fields
).
How to use
Basic
The form
function needs a callback that returns a fields configuration object.
<script>
import { form, bindClass } from 'svelte-forms';
let name = '';
const myForm = form(() => ({
name: { value: name, validators: ['required'] }
}));
</script>
<style>
:global(input.invalid) {
border-color: red;
}
</style>
<form>
<input
type="text"
name="name"
bind:value={name}
use:bindClass={{ form: myForm }} />
<button disabled="{!$myForm.valid}">Login</button>
</form>
Advanced
<script>
import { form } from 'svelte-forms';
let name = "";
let email = "";
const usernameIsNotTaken = async value =>
fetch(`https://jsonplaceholder.typicode.com/users?username=${value}`)
.then(d => d.json())
.then(d => ({
name: "usernameIsNotTaken",
valid: !d.length
}));
const loginForm = form(
() => ({
name: {
value: name,
validators: ["required", "min:6", usernameIsNotTaken]
},
email: { value: email, validators: ["required", "email"] }
}),
{
initCheck: true,
validateOnChange: false,
stopAtFirstError: false,
stopAtFirstFieldError: false
}
);
</script>
<form>
<input type="text" bind:value={name} />
{#if $loginForm.fields.name.errors.includes('required')}
<p>The name is required</p>
{/if}
{#if $loginForm.fields.name.errors.includes('min')}
<p>The name should be at least 6 characters</p>
{/if}
{#if $loginForm.fields.name.pending}
<p>Checking name availability..</p>
{/if}
{#if $loginForm.fields.name.errors.includes('usernameIsNotTaken')}
<p>This username is already taken</p>
{/if}
<input
type="email"
bind:value={email}
class:valid={$loginForm.fields.email.valid} />
{#if $loginForm.fields.email.errors.includes('email')}
<p>The email is invalid</p>
{/if}
<button on:click|preventDefault={() => loginForm.validate()}>
Validate form
</button>
<button disabled={!$loginForm.valid}>Login</button>
</form>
API
form(callback: () => fieldConfigurationObject, config ): StoreObservable
Creates a new form validator and returns a store observable, thus you can automatically subscribe with the famous $
reserved token.
The store value represents a form validation object.
As second parameter you can pass a configuration object with the following properties
property | description |
---|---|
stopAtFirstError |
Stops validation after first error encountered. Default: false
|
stopAtFirstFieldError |
Stops validation after first error encountered per field. Default: true
|
initCheck |
Tells the form to validate or not the fields at initialization. Default: true
|
validateOnChange |
Tells the form to validate after changes to fields. Default: true
|
The form comes with a handy functions:
-
validate
that performs a validation on call. -
reset
that reset the form if needed.
const myForm = form(() => ({ name: { value: '', validators: ['required'] } }));
function manualValidation() {
myForm.validate();
myForm.reset();
}
bindClass({ form: StoreObservable, name: string, valid: string = 'valid', invalid: string = 'invalid', dirty: string = 'dirty' })
<input type="text" name="username" use:bindClass={{ form: loginForm }} /> <input type="text" use:bindClass={{ form: loginForm, name: "username" }} />
Automatically adds valid
or invalid
and dirty
(default value) classes to the input:
- Adds
valid
orinvalid
IF the form is dirty AND every rule is matched. - Adds
dirty
if field is dirty.
If bindClass
is used on a DOM node that has an attribute name
, it will check for this field.
Otherwise you can set the field by setting the name
parameter.
You can override the classes by passing the parameters valid
and invalid
.
<input type="text" use:bindClass={{ form: loginForm, valid: 'ok', invalid: 'ko' }} />
Fields configuration Object
The keys of the object represent the name of the fields and their validator configurations
{ name: { value: name, validators: ['required'], enabled: true, ...data } }
Validator configuration object
property | description |
---|---|
value |
Reference the value to be check |
validators |
An array representing the validations that need to be performed on the field. See @validators |
enabled |
Boolean defining if the field should be included in the validation process. Default true
|
Additional data may be included here (but has no effect).
Form validation object
property | type | description |
---|---|---|
valid |
boolean | If the form is valid or not |
dirty |
boolean | If any field has a different value than when the form was initialized |
fields |
Object | An object where the keys are the names as described in the fields configuration object and their respective field validation objects which represent the current state of the form |
oldFields |
Object | An object where the keys are the names as described in the fields configuration object and their respective field validation objects which represent the last state of the form |
let name = '';
const loginForm = form(() => ({
name: { value: name, validators: ['required', 'min:3'], extraData: '' }
}));
// Form
$loginForm.valid; // false
$loginForm.dirty; // false
// Current state of name field
$loginForm.fields.name.valid; // false
$loginForm.fields.name.pending; // false
$loginForm.fields.name.errors; // ['required', 'min']
$loginForm.fields.name.enabled; // true
$loginForm.fields.name.data; // { value, validators, extraData }```
Field validation object
An object that represents a validated field.
property | type | description |
---|---|---|
valid |
boolean | If the field is valid or not |
errors |
Array | An array representing the errors name in case if the field is invalid |
pending |
boolean | If there are any async validators, will be true until all of them have been resolved |
enabled |
boolean | If the field is enabled or not |
data |
object | The validator configuration object |
Validators
"between:numberA:numberB"
between { validators: ['between:3:16'] }`
If the value is a number, checks the number is between numberA
and numberB
If the value is a string, checks the string length is between numberA
and numberB
"email"
email { validators: ['email'] }`
Check the value is an email
"equal:number"
equal { validators: ['equal:42'] }`
If the value is a number, checks the number is equal to number
If the value is a string, checks the string length is equal to number
"min:number"
min { validators: ['min:42'] }`
If the value is a number, checks the number is greater than number
If the value is a string, checks the string length is greater than number
"max:number"
max { validators: ['max:42'] }`
If the value is a number, checks the number is lesser than number
If the value is a string, checks the string length is lesser than number
"required"
required { validators: ['required'] }`
Mark the field as required
"url"
url { validators: ['url'] }`
Check the value is an URL
Custom validator
If you want to use your own validator, you can pass a function, it will receive the value to be checked as parameter.
It must return an object as follow: { valid: boolean, name: string }
valid
: describes if the condition is matched
name
: the name of the validator in case of failure
const empty = value => ({ valid: value === '', name: 'empty' });
{
name: {
value: name,
validators: [empty]
}
}
You can of course mix regular validators and custom validators.
Async validator
Nothing more to do, just mark your function as async
or return a Promise
.
svelte-forms
will handle things for you.
In addition, there will be a pending
property inside the field validation object telling if the validator has been resolved or is still pending.
TODO
- Testing
- Examples