Validation
Learn how to validate elements and create custom rules in Vueform.
Validation Rules
We can pass an array
of rules to an element or a string
where rules are separated by |
:
<TextElement :rules="['required', 'email']" />
<TextElement rules="required|email" />
Validate On
To decide when to validate elements we can set validate-on
prop on form level:
<template>
<Vueform validate-on="">
<TextElement :rules="['required', 'email']" ... />
<ButtonElement button-label="Submit" submits ... />
</Vueform>
</template>
The form only validates on submit if validate-on
is empty.
It can contain to other values joined with |
. Possible values: change
and step
:
<Vueform validate-on="change|step">
If change
is present the elements will be validated when their values are changed.
If step
is present they will be validated when using form steps before moving to the next step.
The validateOn
option can be set globally in vueform.config.js
:
// vueform.config.js
import { defineConfig } from '@vueform/vueform'
export default defineConfig({
validateOn: 'change|step',
// ...
})
Debounce
Certain rules should not be checked instantly as the user inputs data. For example when an element has email
rule it's better to display an error message only a second after the user has stopped writing. This can be achieved by passing the number of milliseconds that should elapse after the last user input to :debounce
prop:
<TextElement :debounce="1000" rules="required|email" />
Passing debounce
as a prop will apply delay to all validation rules. If we want to apply it only for one, we can pass it directly to the rule:
<TextElement rules="required|email:debounce=1000" />
If the element value is empty the debounce value will be ignored.
Nullable
We can use the nullable
rule to ignore further rules if the element's value is empty.
Here's email
rule without nullable
:
<TextElement rules="email" />
And with nullable
:
<TextElement rules="nullable|email" />
Asnyc Rules
Validation rules can asynchronous. For example unique
rules sends a request to and endpoint and waits for the answer before deciding if the element's value is valid:
<TextElement rules="nullable|unique:users" />
Validation rule endpoints can be configured in vueform.config.js
. See configuration options at unique
and exists
rules.
Dependent Rules
Validation rules can compare an element's value with an other and trigger validation check when any of them changes. For example confirmed
rule needs to have an other element with the same name, suffixed with _confirmation
to have the same value:
<TextElement name="password" rules="required|confirmed" ... />
<TextElement name="password_confirmation" rules="required" ... />
Conditional Rules
Sometimes we only want to apply a validation rule to an element under certain conditions. To do that we must define rules as an array
and set the rule as an object:
<CheckboxElement name="newsletter" ... />
<TextElement name="email" :rules="[
{
required: ['newsletter', '==', true]
}
]" ... />
The key of the object is the name of the rule and the value is an array. The first item of the array must be the path
of the other element. The second is an operator that should define the type of comparison. The third is the expected value of the other element.
If you want to check for equality you can leave the operator and pass the expected value as the second param:
required: ['newsletter', true]
Available operators:
==
- expect equality!=
- expect inequality>
- expect the other element's value(s) to be higher>=
- expect the other element's value(s) to be higher or equal<
- expect the other element's value(s) to be lower<=
- expect the other element's value(s) to be lower or equal^
- expect the other element's value to start with$
- expect the other element's value to end with*
- expect the other element's value to containin
- expect to be among an array of valuesnot_in
- expect not to be among an array of valuestoday
- expect to be todaybefore
- expect to be before a date (value can be aYYYY-MM-DD
date string ortoday
)after
- expect to be after a date (value can be aYYYY-MM-DD
date string ortoday
)
The expected value can also be defined as an array
in which case any of its values will fulfill the condition:
<template>
<SelectElement name="delivery" :items="{
ups: 'UPS',
fedex: 'FedEx',
shop: 'In person'
}" ... />
<TextElement name="phone" :rules="[
{
required: ['delivery', ['ups', 'fedex']]
}
]" ... />
</template>
AND Conditions
Multiple conditions can be applied by wrapping conditions in an array:
<template>
<SelectElement name="delivery" :items="{
ups: 'UPS',
fedex: 'FedEx',
shop: 'In person'
}" ... />
<TextElement name="phone" :rules="[
{
required: [
['delivery', ['ups', 'fedex']],
['other_condition', 'expected value'],
]
}
]" ... />
</template>
In this case both delivery
and other_condition
need to satisfy their conditions.
OR Conditions
To create or conditions you might wrap the conditions in an other array:
<template>
<SelectElement name="delivery" :items="{
ups: 'UPS',
fedex: 'FedEx',
shop: 'In person'
}" ... />
<!-- Either `delivery` OR `other_condition` need to satisfy the condition -->
<TextElement name="phone" :rules="[
{
required: [
[
['delivery', ['ups', 'fedex']],
],
[
['other_condition', 'expected value'],
]
]
}
]" ... />
</template>
In this case either delivery
or other_condition
need to satisfy their conditions.
In or condition groups multiple conditions can be wrapped and they can be combined with single conditions:
<template>
<SelectElement name="delivery" :items="{
ups: 'UPS',
fedex: 'FedEx',
shop: 'In person'
}" ... />
<TextElement name="phone" :rules="[
{
required: [
[
['condition_1', 'expected value'],
['condition_2', 'expected value'],
],
[
['condition_3', 'expected value'],
['condition_4', 'expected value'],
],
['condition_5', 'expected value']
]
}
]" ... />
</template>
In this case condition_1
or condition_2
AND condition_3
or condition_4
AND condition_5
need to fulfill their condition.
Functional Conditions
We can also pass a function as a condition for more complex use-cases:
<template>
<CheckboxElement name="support" ... />
<SelectElement name="delivery" :items="{ ... }" ... />
<TextElement name="phone" :rules="[
{
required: (form$, Validator) => {
Validator.watch(['support', 'delivery'])
return form$.el$('support')?.value === true ||
['ups', 'fedex'].indexOf(form$.el$('delivery')?.value) !== -1
}
}
]" ... />
</template>
The condition function receives form$
as its first param, which is the instance of Vueform
component and Validator
as second.
We can use Validator.watch
method to automatically revalidate the current element when another element changes. The Validator.watch
accepts an array of element paths or a single element path
.
Functional conditions can also wrapped in arrays or used in or condition groups.
Multilingual Rules
Certain elements can have multiple values in different languages. For example for TTextElement
we can set different rules for different languages:
<TTextElement name="title" :rules="{
en: 'required|max:255',
zh: 'max:255',
}" />
Error Messages
When an element has failing rules the first one's error message will be displayed under the element:
<template>
<Vueform>
<TextElement rules="required|email" />
</Vueform>
</template>
If the element has label
, floating
or a placeholder
those will be used as element names in the error message (in this order).
We can explicitly define the name we want to use in the error message with field-name
option:
<template>
<Vueform>
<TextElement rules="required|email" field-name="Email address" />
</Vueform>
</template>
If none of the above ones are defined, the name
will be transformed to element name, using uppercase first letter and replacing _
and -
with spaces.
Form Errors
The form collects all validation errors from elements in FormErrors
component which is displayed above the form by default:
It can be disabled locally with :display-errors
prop:
<template>
<Vueform :display-errors="false">
It can also be disabled globally in vueform.config.js
:
// vueform.config.js
import { defineConfig } from '@vueform/vueform'
export default defineConfig({
displayErrors: false,
// ...
})
Custom Error Messages
By default validation messages come from the locale file's validation
object entry. Error messages can be replaced by passing an object to :messages
prop:
<template>
<Vueform>
<TextElement rules="required" :messages="{
required: 'Please fill in this field'
}" />
</Vueform>
</template>
The object key is the name of the validator, and the value is the custom message.
We can use :attribute
to reference the element's name in the error message:
{ required: 'Please fill in :attribute field' }
Error messages can also be replaced on form level:
<template>
<Vueform :messages="{
required: 'Please fill in this field'
}" />
</template>
Or globally when importing the locale in vueform.config.js
:
// vueform.config.js
import { defineConfig } from '@vueform/vueform'
import en from '@vueform/vueform/locales/en'
en.validation.required = 'Please fill in :attribute field'
export default defineConfig({
locales: { en },
// ...
})
Custom Errors and Messages
We can add custom errors and messages to our form using the append
and prepend
methods of the form's messageBag
:
<template>
<Vueform ref="form$">
<TextElement name="name" rules="required" />
</Vueform>
</template>
<script setup>
import { ref, onMounted } from 'vue'
const form$ = ref(null)
onMounted(() => {
form$.value.messageBag.append('Appended error')
form$.value.messageBag.prepend('Prepended error')
form$.value.messageBag.append('Appended message', 'message')
form$.value.messageBag.prepend('Prepended message', 'message')
})
</script>
<template>
<Vueform ref="form$">
<TextElement name="name" rules="required" />
</Vueform>
</template>
<script>
export default {
mounted() {
this.$refs.form$.messageBag.append('Appended error')
this.$refs.form$.messageBag.prepend('Prepended error')
this.$refs.form$.messageBag.append('Appended message', 'message')
this.$refs.form$.messageBag.prepend('Prepended message', 'message')
}
}
</script>
Appended and prepended form errors are displayed before and after form errors in FormErrors
component. Messages are displayed in FormMessages
component.
Messages and errors can be removed and cleared:
messageBag.clear() // clears all errors and messages
messageBag.clear('errors') // clears all errors
messageBag.clear('messages') // clears all messages
messageBag.clearPrepended() // clears all prepended errors and messages
messageBag.clearPrepended('errors') // clears prepended errors
messageBag.clearPrepended('messages') // clears prepended messages
messageBag.clearAppended() // clears all appended errors and messages
messageBag.clearAppended('errors') // clears appended errors
messageBag.clearAppended('messages') // clears appended messages
messageBag.remove('Lorem ipusm') // removes 'Lorem ipsum' entry from errors and messages
messageBag.remove('Lorem ipusm', 'errors') // removes 'Lorem ipsum' entry from errors
messageBag.remove('Lorem ipusm', 'messages') // removes 'Lorem ipsum' entry from messages
Errors and messages can be added to an element's messageBag
as well:
<template>
<Vueform ref="form$">
<TextElement name="name" rules="required" />
</Vueform>
</template>
<script setup>
import { ref, onMounted } from 'vue'
const form$ = ref(null)
onMounted(() => {
form$.value.el$('name').messageBag.append('Appended error')
form$.value.el$('name')..messageBag.prepend('Prepended error')
form$.value.el$('name')..messageBag.append('Appended message', 'message')
form$.value.el$('name')..messageBag.prepend('Prepended message', 'message')
})
</script>
<template>
<Vueform ref="form$">
<TextElement name="name" rules="required" />
</Vueform>
</template>
<script>
export default {
mounted() {
this.$refs.form$.el$('name').messageBag.append('Appended error')
this.$refs.form$.el$('name').messageBag.prepend('Prepended error')
this.$refs.form$.el$('name').messageBag.append('Appended message', 'message')
this.$refs.form$.el$('name').messageBag.prepend('Prepended message', 'message')
}
}
</script>
When errors and messages are added to an element only the first appears under the element from each group. Errors manually added to elements' messageBag
will be collected in form errors, while messages will not be included in form messages.
Manual Validation
Form validation can be manually triggered with validate()
method:
<template>
<Vueform ref="form$">
<TextElement name="name" rules="required" ... />
<TextElement name="email" rules="required" ... />
</Vueform>
</template>
<script setup>
import { ref, onMounted } from 'vue'
const form$ = ref(null)
onMounted(() => {
form$.value.validate()
})
</script>
<template>
<Vueform ref="form$">
<TextElement name="name" rules="required" ... />
<TextElement name="email" rules="required" ... />
</Vueform>
</template>
<script>
export default {
mounted() {
this.$refs.form$.validate()
}
}
</script>
It can be also triggered for elements:
<template>
<Vueform ref="form$">
<TextElement name="name" rules="required" ... />
<TextElement name="email" rules="required" ... />
</Vueform>
</template>
<script setup>
import { ref, onMounted } from 'vue'
const form$ = ref(null)
onMounted(() => {
form$.value.el$('name').validate()
})
</script>
<template>
<Vueform ref="form$">
<TextElement name="name" rules="required" ... />
<TextElement name="email" rules="required" ... />
</Vueform>
</template>
<script>
export default {
mounted() {
this.$refs.form$.el$('name').validate()
}
}
</script>
Validation can be reset with resetValidators()
:
<template>
<Vueform ref="form$">
<TextElement name="name" rules="required" ... />
<TextElement name="email" rules="required" ... />
<ButtonElement name="reset" button-label="Reset Name validators" @click="resetNameValidators">
<ButtonElement name="reset" button-label="Reset all validators" @click="resetAllValidators">
</Vueform>
</template>
<script setup>
import { ref, onMounted } from 'vue'
const form$ = ref(null)
const resetNameValidators = () => {
form$.value.el$('name').resetValidators()
}
const resetAllValidators = () => {
form$.value.resetValidators()
}
onMounted(() => {
form$.value.validate()
})
</script>
<template>
<Vueform ref="form$">
<TextElement name="name" rules="required" ... />
<TextElement name="email" rules="required" ... />
<ButtonElement name="reset" button-label="Reset Name validators" @click="resetNameValidators">
<ButtonElement name="reset" button-label="Reset all validators" @click="resetAllValidators">
</Vueform>
</template>
<script>
export default {
methods: {
resetNameValidators() {
this.$refs.form$.el$('name').resetValidators()
},
resetAllValidators() {
this.$refs.form$.resetValidators()
}
},
mounted() {
this.$refs.form$.validate()
}
}
</script>
Available Validation Rules
Here's the list of available validator rules:
accepted
The value must be true
, 'true'
, 'yes'
, 'on'
, '1'
or 1
.
active_url
The value must be an URL with active A or AAAA type DNS record. The validator must be implemented on the backend which should return a true
or false
response.
The endpoint must be set in vueform.config.js
:
// vueform.config.js
import { defineConfig } from '@vueform/vueform'
export default defineConfig({
endpoints: {
activeUrl: {
url: '/validators/active-url',
method: 'POST'
}
},
// ...
})
Alternatively we can specify it as an async function
that returns a true
or false
value:
// vueform.config.js
import axios from 'axios'
import { defineConfig } from '@vueform/vueform'
export default defineConfig({
endpoints: {
activeUrl: async (value, el$, form$) => {
const res = await axios.post('/my-active-url-checker', {
value,
})
return res.data // should be `true` or `false`
}
},
// ...
})
after:date
The value must be after a given date. The date
parameter can be an exact date like 2020-01-01
, a relative date which is either today
, tomorrow
or yesterday
or the path
to an other element.
// being an exact date
'after:2018-01-01'
// being a relative date
'after:today'
// being an other elements's path
'after:checkin_date'
after_or_equal:date
It's the same as after rule, except that the value must be after or equal to a given date.
alpha
The value can only contain alphabetic characters.
alpha_dash
The value can only contain numbers, alphabetic characters, dash -
and underscore _
.
alpha_num
The value can only contain numbers and alphabetic characters.
array
The value must be an array.
before:date
It's the same as after rule, except that the value must be before a given date.
before_or_equal:date
It's the same as after rule, except that the value must be before or equal to a given date.
between:min,max
The value must be between the size of min and max. The size is evaluated the same way as described at size rule.
boolean
The value must be some form of a boolean which is either true
, false
, 1
, 0
, '1'
or '0'
.
captcha
Validates if the captcha challenge has been passed. Automatically assigned to each captcha elements - no need to assign manually.
completed
Validates if the phone number is completed when masks are enabled (used only in PhoneElement
).
confirmed
The value must identical to an other element's value which has the same name ending with _confirmation
.
password: {
type: 'text',
inputType: 'password',
rules: 'confirmed'
},
password_confirmation: {
type: 'text',
inputType: 'password',
label: 'Password Again'
}
date
The value must be a valid date.
date_equals:date
The value must match an exact date.
date_format:format
The value must match a given date format using Date Formatting Tokens.
different:path
The value must be different from an other element's value.
digits:value
The value must be numeric and have an exact length of value.
digits_between:min,max
The value must be numeric and have a length between min and max.
dimensions
The value must be an image with dimension constraints. Available constraints:
- min_width
- min_height
- max_witdth
- max_height
- height
- width
- ratio
The ratio can be a float, like 0.66
or a statement like 2/3
which represents width / height ratio.
'dimensions:min_width=768'
'dimensions:min_height=1024'
'dimensions:min_width=768,ratio=2/3'
distinct
The value must be a unique item of an array.
favorite_numbers: {
type: 'list',
label: 'Favorite numbers:',
element: {
type: 'text',
placeholder: 'Number',
rules: 'distinct'
}
}
The value must be a valid email format.
exists:param1,param2,...
The value must be confirmed by an endpoint that exist in database. It does not specify any required params, but we can use them to identify a validation request in the backend.
For example, let's take the following rule definition: exists:users
. The users
param is just a string that the backend receives in the params
(request) param:
$params = $_REQUEST['params'];
$type = $params[0]; // will be 'users'
Params can be used to identify requests:
$value = $_REQUEST['value']; // the value of the input field
$name = $_REQUEST['name']; // the name of the input field
$params = $_REQUEST['params'];
$type = $params[0];
switch($type) {
case 'users':
return ... // check value against users
case 'product_identifiers':
return ... // check value against product identifiers
case 'slugs':
return ... // check value against slugs
}
The backend should return true
if the given value
exist in the database and therefore the field value should be considered valid.
If a param's name equals to the name of a field in the form, the value of that will be sent instead of the param name. So for example if exists:users,id
is the rule and the form has a field with id
name, the request params will be sent:
// request params sent to `exists` endpoint
requestParams: {
value: 'john@doe.com',
name: 'email',
params: [
'users',
5984
]
}
And you can access the value of id
field using the params
object:
$value = $_REQUEST['value']; // the value of the input field - 'john@doe.com'
$name = $_REQUEST['name']; // the name of the input field - 'email'
$params = $_REQUEST['params'];
$type = $params[0]; // will be 'users'
$id = $params[1]; // will be the value of the 'id' field in the same form - 5984
This way we can send field values dynamically to the backend to validate requests (eg. excluding the user's ID from the database check).
The endpoint where all the exists
requests submitted can be configured in vueform.config.js
's endpoints.exists
section:
// vueform.config.js
import { defineConfig } from '@vueform/vueform'
export default defineConfig({
endpoints: {
exists: {
url: '/validators/exists',
method: 'POST'
}
},
// ...
})
Alternatively we can specify it as an async function
that returns a true
or false
value:
// vueform.config.js
import axios from 'axios'
import { defineConfig } from '@vueform/vueform'
export default defineConfig({
endpoints: {
exists: async (value, name, params, el$, form$) => {
const res = await axios.post('/my-exists-checker', {
value,
name,
params,
})
return res.data // should be `true` or `false`
}
},
// ...
})
file
The value must be an instance of File.
filled
The value must be not empty.
gt:path
The value must be greater than the size of a given element. The size is evaluated the same way as described at size rule.
gte:path
The value must be greater than or equal to the size of a given element. The size is evaluated the same way as described at size rule.
image
The value must a file with jpg
, jpeg
, png
, bmp
, gif
, svg
or webp
extension.
in:foo,bar,...
The value must be one of the provided values.
role: {
type: 'select',
label: 'Role',
items: {
admin: 'Admin',
editor: 'Editor'
},
rules: 'in:admin,editor'
}
in_array:path.*
The value must be present in an other element's array value.
integer
The value must be an integer.
ip
The value must be a valid IP address.
ipv4
The value must be a valid IPv4 address.
ipv6
The value must be a valid IPv6 address.
json
The value must be a valid JSON string.
lt:path
The value must be lower than the size of a given element. The size is evaluated the same way as described at size rule.
lte:path
The value must be lower than or equal to the size of a given element. The size is evaluated the same way as described at size rule.
max:value
The size of the value must be lower than or equal to max. The size is evaluated the same way as described at size rule.
mimetypes:text/plain,...
The value must be an instance of File and have one of the listed mime-type.
mimes:zip,rar,...
The value must be an instance of File and have one of the listed extensions.
min:value
The size of the value must be at least value. The size is evaluated the same way as described at size rule.
not_in:foo,bar,...
The value must not be one of the provided values.
not_regex:pattern
The value must not match the provided regex pattern.
'not_regex:/^.+$/i'
When using pipe
|
in the pattern it's recommended to define the rules as array instead of a string.
nullable
Certain rules should only execute if the input has value, otherwise it should be ignored. For example if the user can optionally fill in his birthday, the date format should only be validated if the input is filled:
birthday: {
type: 'date',
label: 'Birthday',
rules: 'nullable|date_format:YYYY-MM-DD'
}
numeric
The value must be numeric.
regex:pattern
The value must match the provided regex pattern.
'regex:/^.+$/i'
When using pipe
|
in the pattern it's recommended to define the rules as array instead of a string.
required
The value must not be empty. The value is considered empty as the following:
- the value is
null
- the value is
undefined
- if the value is a string it's
''
- if the value is an array it contains no items
- if the value is a File object it's
name
is empty.
same:path
The value must be the same as the given element's value.
password: {
type: 'password',
rules: 'same:password_again'
},
password_again: {
type: 'password',
label: 'Password Again'
}
If used in nested elements like GroupElment
or ObjectElement
the reference must include the full path using .
dot syntax (eg. parent.password_again
).
size:value
The size of the value must be exactly as a given value. Size is calculated as the following:
- if the value is string then it's the length of the string
- if the value is numeric then it's the actual numeric value
- if the value is array then it's the length of the array
- if the value is File then it's the size of the file in KB.
string
The value must be a string.
timezone
The value must be a valid timezone, eg. 'America/Los_Angeles'
.
unique:param1,param2,...
The value must be confirmed by an endpoint that doesn't exist in database. It does not specify any required params, but we can use them to identify a validation request in the backend.
For example, let's take the following rule definition: unique:users
. The users
param is just a string that the backend receives in the params
(request) param:
$params = $_REQUEST['params'];
$type = $params[0]; // will be 'users'
Params can be used to identify requests:
$value = $_REQUEST['value']; // the value of the input field
$name = $_REQUEST['name']; // the name of the input field
$params = $_REQUEST['params'];
$type = $params[0];
switch($type) {
case 'users':
return ... // check value against users
case 'product_identifiers':
return ... // check value against product identifiers
case 'slugs':
return ... // check value against slugs
}
The backend should return true
if the given value
does not exist (unique) in the database and therefore the field value should be considered valid.
If a param's name equals to the name of a field in the form, the value of that will be sent instead of the param name. So for example if unique:users,id
is the rule and the form has a field with id
name, the request params will be sent:
// request params sent to `unique` endpoint
requestParams: {
value: 'john@doe.com',
name: 'email',
params: [
'users',
5984
]
}
And you can access the value of id
field using the params
object:
$value = $_REQUEST['value']; // the value of the input field - 'john@doe.com'
$name = $_REQUEST['name']; // the name of the input field - 'email'
$params = $_REQUEST['params'];
$type = $params[0]; // will be 'users'
$id = $params[1]; // will be the value of the 'id' field in the same form - 5984
This way we can send field values dynamically to the backend to validate requests (eg. excluding the user's ID from the database check).
The endpoint where all the unique
requests submitted can be configured in vueform.config.js
's endpoints.unique
section:
// vueform.config.js
import { defineConfig } from '@vueform/vueform'
export default defineConfig({
endpoints: {
unique: {
url: '/validators/unique',
method: 'POST'
}
},
// ...
})
Alternatively we can specify it as an async function
that returns a true
or false
value:
// vueform.config.js
import axios from 'axios'
import { defineConfig } from '@vueform/vueform'
export default defineConfig({
endpoints: {
unique: async (value, name, params, el$, form$) => {
const res = await axios.post('/my-unique-checker', {
value,
name,
params,
})
return res.data // should be `true` or `false`
}
},
// ...
})
url
The value must be a valid URL format.
uuid
The value must be a valid UUID format.
Custom Validation Rules
We can create custom validation rules by extending Validator
class:
<template>
<Vueform>
<TextElement :rules="[uppercase]" name="code" />
</Vueform>
</template>
<script setup>
import { Validator } from '@vueform/vueform'
const uppercase = class extends Validator {
check(value) {
return /^[A-Z]*$/.test(value)
}
}
</script>
<template>
<Vueform>
<TextElement :rules="[uppercase]" />
</Vueform>
</template>
<script>
import { Validator } from '@vueform/vueform'
const uppercase = class extends Validator {
check(value) {
return /^[A-Z]*$/.test(value)
}
}
export default {
data() {
return {
uppercase,
}
}
}
</script>
The check
method validates whether the value only contains uppercase letters.
Custom Error Message
If the value is invalid a generic error message will be displayed from locale's vueform.defaultMessage
. We can replace this by adding a custom message to the rule:
const uppercase = class extends Validator {
get msg() {
return 'The text must only contain uppercase letters'
}
check(value) {
return /^[A-Z]*$/.test(value)
}
}
Message Params
We can use :attribute
param in our error message that will be replaced by the element's name. By default the element's name equals to its label
or if there's no label then the placeholder
or if that's not defined either then the element's name
, uppercasing its first letter:
const uppercase = class extends Validator {
get msg() {
return 'The :attribute must only contain uppercase letters'
}
check(value) {
return /^[A-Z]*$/.test(value)
}
}
We can add other params to the error message by defining get messageParams
:
const uppercase = class extends Validator {
get msg() {
return 'The :attribute must only contain :type letters'
}
get messageParams () {
return {
attribute: this.attributeName,
type: 'UPPERCASE'
}
}
check(value) {
return /^[A-Z]*$/.test(value)
}
}
Rule Params
We can add params to our rule by wrapping it in an array
and pass params as the second second item. Then we can get them via attributes
.
Let's say we only want to allow character between A-H
:
<template>
<Vueform>
<TextElement :rules="[
[uppercase, ['A', 'H']]
]" />
</Vueform>
</template>
<script setup>
import { Validator } from '@vueform/vueform'
const uppercase = class extends Validator {
get from () {
return this.attributes[0] || 'A'
}
get to () {
return this.attributes[1] || 'Z'
}
check(value) {
let regexp = new RegExp(`^[${this.from}-${this.to}]*$`)
return regexp.test(value)
}
}
</script>
<template>
<Vueform>
<TextElement :rules="[
[uppercase, ['A', 'H']]
]" />
</Vueform>
</template>
<script>
import { Validator } from '@vueform/vueform'
const uppercase = class extends Validator {
get from () {
return this.attributes[0] || 'A'
}
get to () {
return this.attributes[1] || 'Z'
}
check(value) {
let regexp = new RegExp(`^[${this.from}-${this.to}]*$`)
return regexp.test(value)
}
}
export default {
data() {
return {
uppercase,
}
}
}
</script>
Once the rule is registered globally we can provide params after the rule name using a colon :
, separated by commas ,
:
<TextElement rules="uppercase:A,H" ... />
Using Rule Params in Message
We can combine our rule params with message params:
const uppercase = class extends Validator {
get msg() {
return 'The :attribute must only contain [:from-:to] letters'
}
get messageParams () {
return {
attribute: this.attributeName,
from: this.from,
to: this.to,
}
}
get from () {
return this.attributes[0] || 'A'
}
get to () {
return this.attributes[1] || 'Z'
}
check(value) {
let regexp = new RegExp(`^[${this.from}-${this.to}]*$`)
return regexp.test(value)
}
}
Watching For Change
Let's say we have a custom rule which needs to watch a property and revalidate when that property changes.
We can use the rule's init()
method to create a watcher and revalidate the field when the value changes:
<script setup>
import { ref, watch, onMounted } from 'vue'
const valueToWatch = ref(1)
const customRule = class extends Validator
{
init() {
watch(valueToWatch, () => {
this.revalidate()
})
}
check(value) {
// ...
}
}
onMounted(() => {
setTimeout(() => {
// This will trigger revalidation of the field that uses the custom rule
valueToWatch.value++
}, 1000)
})
</script>
Async Validation
Validation rules can also be async
by adding get isAsync()
which returns true
:
const uppercase = class extends Validator {
get isAsync() {
return true
}
async check(value) {
return (await axios.get('/validator/uppercase')).data.valid
}
}
While async validation is in progress a loading spinner will automatically appear on the right side of the input.
Registering Rule Globally
Custom validation rules can be registered globally in vueform.config.js
:
// vueform.config.js
import { defineConfig, Validator } from '@vueform/vueform'
const uppercase = class extends Validator {
async check(value) {
return /^[A-Z]*$/.test(value)
}
}
export default defineConfig({
rules: {
uppercase,
},
// ...
})
Once registered, they can be used as strings:
<TextElement rules="required|uppercase" ... />
Adding Rule Message to Locale
An error message can be added to the global locale instead of using get message()
:
// vueform.config.js
import { defineConfig, Validator } from '@vueform/vueform'
import en from '@vueform/vueform/locales/en'
en.validation.uppercase = 'The text must only contain uppercase letters'
const uppercase = class extends Validator {
check(value) {
return /^[A-Z]*$/.test(value)
}
}
export default defineConfig({
rules: {
uppercase,
},
locales: { en }
// ...
})