Validation
Validation can be set up against each field and can take a function or a string to evaluate against. Fields that contain validation are implicitly required ( i.e. they are required by default ). If you want a field to contain validation, but _not _be required ( i.e. only run the validation when data is present ), you must set the required
attribute to false
. For example:
let vm = new Vue({
el: '#app',
data: {
form: {},
model: {
name: '',
email: '',
lname: ''
}
fields: [
{
key: 'name',
type: 'text',
required: true
},
{
key: 'lname',
type: 'text',
validators: {
length: 'model[ field.key ].length > 3'
}
},
{
key: 'email',
type: 'text',
required: false,
validators: {
looksOk: function(field, model, next){
next(model[ field.key ].indexOf('@') >= 0);
}
}
}
]
}
});
In the above example the name field is required, the lname field must be longer than 3 characters and is also required, and the email field must have a '@' present but is not required. This means that if the user leaves the email field blank, the form will be valid. If they enter a value into the email field and it doesn't pass the validation, then it will not be valid.
Validation Methods
Sometimes you want to re-run the validation checks before the form is submitted. You can do this by calling the validate()
method on the FormlyForm
component. This returns a promise which should always resolve unless their is an actual error.
Note that validate()
will resolve even if the form is invalid. It should only reject if there was some actual error with the validation. With this in mind you should still check the validity of the form before submitting in.
An example:
<template>
<form v-on:submit="handleSubmit()">
<formly-form :model="model" :form="form" :fields="fields" ref="loginForm"></formly-form>
</form>
</template>
<script>
export default {
methods: {
handleSubmit(){
this.$refs.loginForm.validate()
.then(()=>{
if ( !this.form.$valid ) return;
// submit form
})
.catch((e)=>{
// do something with the error
});
}
},
data(){
// return all your fields here
}
}
</script>
Validation Types
Expression
You can set the validation to be an expression by simply adding your expression to be evaluated as a string. The variables available to you are field
and model
which hold the currently evaluated field data and the form model data respectively. The expression expects to evaluate to true
to be valid.
e.g. the below will require the email field to equal "[email protected]"
...
{
key: 'email',
validators:{
validEmail: 'model[ field.key ] === "[email protected]"'
}
}
Function & Asynchronous Validation
Note that the use of functions changed significantly in version 2.3.1. The docs for both are below
v2.3.x
For more complicated validation you may wish to use a function. The function must always call the next()
function with a true or false value. True denoting the field is valid and false for invalid. Arguments passed to the function are the field
and model
variables which hold the evaluated field data and the form model data respectively. The next
function is also passed which accepts a boolean value and an optional message parameter. See below for examples of both.
e.g. the below will require one field to equal another:
...
{
key: 'confirmPass',
validators: {
sameAsPass: function(field, model, next){
//assume that 'password' is a previously defined field in the schema
next(model[ field.key ] == model.password);
}
}
}
an example with Asynchronous Validation that fetches the error message from the server:
...
{
key: 'confirmPass',
validators: {
validUsername: function(field, model, next){
axios.post('/auth/checkValidUsername', {
username: model.username
}).then( function(response){
let message = response.message || false;
next(response.status == 'ok', message);
});
}
}
}
v2.2.x
For more complicated validation you may wish to use a function. The function should return a true
value. Arguments passed to the function are the field
and model
variables which hold the evaluated field data and the form model data respectively.
Note that in 2.2 asynchronous validation was not natively supported. There are potential workarounds for this, see this issue for examples.
e.g. the below will require one field to equal another
...
{
key: 'confirmPass',
validators: {
sameAsPass: function(field, model){
//assume that 'password' is a previously defined field in the schema
return model[ field.key ] == model.password;
}
}
}
Object
You can finally pass an object as a validator. This is only required if you are wishing to add or override an error message label ( more on that below ). The object must consist of an expression
which can be either a string or a function as above and a message
which is the message to be parsed.
e.g.
...
{
key: 'confirmPass',
validators: {
sameAsPass: {
expression: function(field, model){
//assume that 'password' is a previously defined field in the schema
return model[ field.key ] == model.password;
},
message: 'Your passwords must match'
},
minLength: {
expression: 'model[field.key].length > 5',
message: 'Your password must be at least 6 characters'
}
}
}
Errors
Errors are stored in the $errors field on the form. Using the above example, if we dumped vm.form.$errors we would see the following structure:
//vm.form.$errors
{
name: {
required: true
},
lname: {
length: true
},
email: {
required: true,
looksOk: true
}
}
Errors will be true
if there is an error ( ie, the field is invalid ) and will become false
when their expectation is met.
Error Messages
You can either globally set error messages or locally set them specific to each field. To globally set them you need to make use of the addValidationMessage
function.
When an error message is set and triggered, you can find that message in the $errors
field as above. The boolean value will instead be the error message.
Note that if you are using a function to validate your field and you leave out the 'message' parameter it will resort to whichever of the following is set. However, if you do add the message parameter it will override the below.
addValidationMessage(key, message)
...
Vue.$formly.addValidationMessage('required', 'This field is required');
the message
parameter also takes two placeholders. %l
and %v
for label and value respectively. E.g. if you added a validation method called 'min' in one of your fields then you could add this global message:
Vue.$formly.addValidationMessage('min', '%l requires a value greater than 10. You entered %v');
Local Messages
You may not always want to add the validation message globally, or you may want to override the message in some cases. You can do that by adding a message
property to the validator. To do this you will need to set the validation as an object instead:
let vm = new Vue({
el: '#app',
data: {
form: {
name: {
type: 'text',
required: true
},
lname: {
type: 'text',
validators: {
length: {
expression: 'model[ field.key ].length > 3',
message: 'You must enter more than 3 characters'
}
}
},
email: {
type: 'text',
required: true,
validators: {
looksOk: {
expression: function(field, model){
return model[ field.key ].indexOf('@') >= 0;
},
message: 'Please enter a valid email'
}
}
}
}
}
});
Valid state
There is also a $valid
attribute that is added to the form and is toggled between true
and false
if all the errors are clear. In the above example, when the user first loads the form, vm.form.$valid
will be false as there are required fields. Once they've filled in those fields and the criteria is met, vm.form.$valid
will become true.