Skip to content

sharpcodepro/svelte-forms

 
 

Repository files navigation

Svelte Forms Validation Build Status

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 function validate that performs a validation on call.

const myForm = form(() => ({ name: { value: '', validators: ['required'] } }));

function manualValidation() {
  myForm.validate();
}

bindClass({ form: StoreObservable, name: string, valid: string = 'valid', invalid: string = 'invalid' })

<input type="text" name="username" use:bindClass={{ form: loginForm }} />
<input type="text" use:bindClass={{ form: loginForm, name: "username" }} />

Automatically adds valid or invalid (default value) classes to the input IF the form is dirty AND every rule is matched.

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 "between:numberA:numberB"

{ 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 "equal:number"

{ 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 "min:number"

{ 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 "max:number"

{ 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

About

Svelte forms validation made easy

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages

  • JavaScript 100.0%