# Validation
There is some cases you will want to add client side validation and showing error messages. The library will trying to make those issues easy to handle.
# Basic validation
Each field can have some rules
, a rule is a function or an object that describe which cases the field value is valid and which cases it is not.
import { Form } from 'form-wrapper-js'
import { required, email } from '@/form/validation.js'
export default {
form: new Form({
email: {
value: null,
rules: [required, email],
},
}),
}
The field email
has 2 rules, those 2 rules are declared in another file called validation.js
.
// form/validation.js
import { isEmail } from 'some-example-library'
export const required = ({ value }) => value !== null && value !== ''
export const email = {
passes: ({ value }) => isEmail(value),
message: ({ label }) => `${label} must be an email.`,
}
there are the 2 "shapes" of validation rule:
- The first is just a function that returns a
boolean
. the error message that will be collect by the Errors collector is the default error message that has been declared in the form options - The second is an object. the object must at least have a
passes
property that should be just like a function rule. the second property ismessage
(that can be also a simplestring
), it should return an error message that will collect by the Errors collector in case the field is not valid.
TIP
By default the validation runs on submission. you can tweak out the options and make your validation runs on field input event or on field blurred event and also you can call the validation manually:
form.$validate()
- will validate the whole formform.$validate('name')
- will validate onlyname
field
check out the options before starting to use those methods.
# Validation`s functions
passes
and message
functions can be very flexible in fact you can create a very powerful validation file or files.
they are both invokes with the same arguments:
- first argument is field, which contains:
const field = {
key: 'email', // field key
label: 'Email', // label of the field
value: 'somthing@example.com', // current value of the field
}
- second argument is the whole form object
Here is a quick example for a complex validation rule:
export const sameAs = sameAsField => {
return {
passes: ({ value, label, key }, form) => value === form[sameAsField],
message: ({ value, label, key }, form) =>
`'${label}' must be equal to '${form.$labels[sameAsField]}'`,
}
}
And here is how you can use it in a Vue component.
import { Form } from 'form-wrapper-js'
import { sameAs } from '@/helpers/validation.js'
export default {
data() {
return {
form: new Form({
password: null,
password_again: {
value: null,
rules: [sameAs('password')],
},
}),
}
},
}
The function sameAs
returns an object and that object is our validation object.
As you can see validation rules can be very powerful and you can customize it as you like.
# Promise base validation
Sometimes you will use a validation library or an http service that's returning a Promise
and not a boolean
you can use it as well by returning the Promise
in the validation function
// form/validation.js
import { RuleValidationError } from 'form-wrapper-js'
import axios from 'axios'
export const isValidEmail = {
passes: ({ value }) =>
axios
.post('https://example.com/is-valid-email', { email: value })
.catch(error => {
if (error.response.status === 422) {
return Promise.reject(new RuleValidationError())
}
}),
message: 'Email is already taken',
}
As you can see passes
function will return an Promise
from the axios
library, if the promise will resolved
the field will be marked as valid, if the promise will rejected and the response status will be 422
(you can do any thing you want), the function will
return a rejected promise with RuleValidationError
WARNING
One thing to understand, you must reject with RuleValidationError
! otherwise the error will bubble up.
You can use form.$isValidating('email')
In case that your Promise
base validating take some time, the function will
return true
if the Promise
base validation is still running and false
if not.
# Dynamic validation
Dynamic validation is useful when there is a field validation that depend on another field, to solve this problem there are 2 options.
- This is the recommended way, create a function that wraps the validation rule (object or function) inside another validation rule:
// This example demonstrates a case that a validation rule is an object and not a function
// In your validation file
export const userRuleIf = (conditionCallback, rule) => {
return {
passes: (field, form) => {
if (!conditionCallback(field, form)) {
return true
}
return rule.passes(field, form)
},
message: rule.message,
}
}
// In your vue file
import { Form } from 'form-wrapper-js'
import { required, useRuleIf } from '@/form/validation.js'
export default {
data() {
return {
form: new Form({
is_developer: false,
programing_languages: {
value: [],
rules: [
userRuleIf((field, form) => form.is_developer === true, required),
]
}
})
}
},
// ...Your vue stuff
}
Of course, you can extend this function and make it more flexible, one way to do so is to support also function validation rules and not only objects.
- Another way is to rebuild the whole rules for the specific field, you can do so with the method
form.$rules.buildFieldRules('fieldName', [rule, rule])
. this option is less performance because there is some process that the library does to build those rules into something that the library can use. but sometimes there are cases that your rule depend on data that lives outside the scope of the Form.
// In your vue file
import { Form } from 'form-wrapper-js'
import { required, useRuleIf } from '@/form/validation.js'
export default {
data() {
return {
is_developer: false,
form: new Form({
programing_languages: {
value: [],
rules: []
}
})
}
},
methods: {
switchIsDeveloper(state) {
this.is_developer = state
this.form.$rules.buildFieldRules(
'programing_languages',
state ? [required] : []
)
}
}
// ...Your vue stuff
}
# Errors
The errors collector will collect errors each time validating a specific field or the whole form,
you can display those errors out with the use of $errors
property.
<template>
<form>
<div>
<input type="text" v-model="form.email" />
<span v-if="form.$errors.has('email')">
{{ form.$errors.getFirst('email') }}
</span>
</div>
</form>
</template>
Each field have an array of errors, form.$errors.get('email')
will return the whole array,
form.$errors.getFirst('email')
will return the first error from that array.
Here is a quick snippet of some methods from the $errors
property you could and should use
from time to time.
form.$errors.any() // checks if there is any error in the form
form.$errors.has('name') // check if there is errors in the `name` field
form.$errors.clear() // will clear all the errors
form.$errors.unset('name') // will clear only `name` field errors
form.$errors.all() // will return all the fields with an array of errors for each of them.
form.$errors.record({
name: ['some errors', 'another one'],
last_name: ['and another one again'],
}) // will fill fields errors
← Field Field Events →