Custom Rules
You can easily add custom rules to VeeValidate, but your custom rules must adhere to a contract or certain structure:
Creating A Custom Rule
Function Form
This is the most basic custom validator form. It consists of only a function that returns either a Boolean or a promise. However, it will have a default error message.
const validator = (value, args) => {
// Return a Boolean or a Promise that resolves to a boolean.
};
Object Form
const validator = {
getMessage(field, args) {
// will be added to default locale messages.
// Returns a message.
},
validate(value, args) {
// Returns a Boolean or a Promise that resolves to a boolean.
}
};
This validator object must have a validate
method and can contain a getMessage
method which will be merged into the current dictionary locale. For multiple languages, you should use the localization API.
TIP
Notice how the getMessage
method receives the field
, which is the name of the field under validation as a first parameter, and how the validate
method receives the value as a first parameter. Both receive the args
array which contains the arguments that were configured with the validation rule. Take a look at the actual implementation of the min rule as an example.
WARNING
As you can see, a validation rule must implement one of the two forms discussed above. Not doing so will throw an exception with a suitable error message detailing what you were missing.
Using The Custom Rule
After creating your custom rule, you can add it to the list of rules using extend(name, validator)
method in the validator instance.
import { Validator } from 'vee-validate';
Validator.extend('truthy', {
getMessage: field => 'The ' + field + ' value is not truthy.',
validate: value => !! value
});
let instance = new Validator({ trueField: 'truthy' });
// Also there is an instance 'extend' method for convenience.
instance.extend('falsy', (value) => ! value);
instance.attach({
name: 'falseField',
rules: 'falsy'
});
TIP
Using any of the extend
either on the class or on an instance will extend all validators with the new validation rule. Extending a new rule that has the same name as an existing rule will silently overwrite it.
Then you can use your rule like any other rule:
<input type="text" name="field" v-validate="'falsy'">
WARNING
When the field under validation is not required, your rule may not be executed at all. This is because VeeValidate skips validation for empty fields if they are not required. You can override this behavior by using v-validate.continues
modifier to force all rules to run.
Args and Rule Configuration
Your rule may provide different results/behavior depending on some configuration, as mentioned before they are passed as an array of values to the validator function, which may not always be optimal, for example a rule with 3 optional parameters would need to recieve all 3 parameters each time just to specify the third parameter.
You can recieve an object instead of an array for your validation rule by providing a paramNames
array in the extend options (third parameter). Which names the params in the array you would normally recieve.
For an example take a look at a basic value between rule implementation:
const isBetween = (value, { min, max } = {}) => {
return Number(min) <= value && Number(max) >= value;
};
// The first param is called 'min', and the second is called 'max'.
const paramNames = ['min', 'max'];
Validator.extend('between', isBetween, {
paramNames // pass it in the extend options.
});
The paramNames isn't really required, but it allows your rule to work in both string/object formats. since there is no way in the string format to pass the named parameters:
between:10,20
The order is what controls the param names in that case. The validator will use the paramNames
to convert the array of strings to an object containing the named parameters as keys with the correct param value. Make sure to order the paramNames
in the same order that the params will be specified in the string format.
WARNING
Locale methods will still recieve the array of args, it will not convert it to an object at the time being due to the possible breaking changes in locale files.
Cross-Field Rules
Sometimes your rules may need to compare the field value against another field value, some built in rules like confirmed
, before
and after
need a target field to compare against.
You can create custom rules that do this as well by setting the hasTarget
property on the extend options object which is the third parameter.
validator.extend('isBigger', (value, [otherValue]) => {
return value >= otherValue;
}, {
hasTarget: true
});
Notice that the other field value will be injected as the first item in the parameter list.
These rules require at least one argument and the target field must have a matching ref
value.
<input v-validate="'confirmed:confirmation'" name="password" type="password" >
<input name="passwordConfirmation" ref="confirmation" type="password" placeholder="Confirm the password">
For validation providers the target field must have a vid
prop set instead of the ref
.
Require-like rules
If you need to define a rule that declares a field as required under specific conditions, you will need to enable the computesRequired
option. Because, by default, VeeValidate doesn't validate non require-like rules if the field has no value. The computesRequired
will tell VeeValidate to run your rule even if the field has no value.
In consequence, your rule must return an object with both valid
and data.required
boolean properties:
validator.extend('my_custom_rule', (value, [otherValue]) => {
// do something and finally return an object like this one:
return {
valid: true, // or false
data: {
required: true // or false
}
};
}, {
computesRequired: true
});
Your rule also has to check for the requirement to be fulfilled.
If data.required
is set to false, the other field rules won't be executed if the field is empty.
TIP
This option is best used when combined with hasTarget
, to make a conditionnal requirement, based on other field values. Like the require_if
rule.
WARNING
You cannot use this option if you want to write an async (promise-based) rule. You rule implementation has to be synchronous.
Non-immediate Rules
VeeValidate triggers initial validation regardless if you used the immediate modifier or not, the difference being if the immediate modifier is set, the errors and flags will be updated.
Sometimes you don't want your rule to be executed, consider a rule that calls to a remote API. Unless the immediate
modifier is set, you don't want the rule to be executed. This can be done by adding immediate
boolean to your extend options.
validator.extend('remote', (value, [otherValue]) => {
// do something
}, {
immediate: false
});
This will skip the rule on the initial validation when the immediate
modifier is not set.
Reasoning
Additionally, you may want to provide a reason for failing the validation that may change the error message. For example, you may be using an external API and the error message is generated there.
To achieve this, your validator function should return an Object
instead of a Boolean
. This object should always contain a valid
property and an optional data
property. The data property will be passed to the message generator function as the third parameter, then you should use the passed data property to modify the output message. The same thing applies to promises as you resolve the promise with an object containing these properties. Here is a custom rule that does just that:
const myRule = {
getMessage(field, params, data) {
return (data && data.message) || 'Something went wrong';
},
validate(value) {
return new Promise(resolve => {
resolve({
valid: value === 'trigger' ? false : !! value,
data: value !== 'trigger' ? undefined : { message: 'Not this value' }
});
});
}
};