form-validation-manager
v2.3.0
Published
VueJs validation manager, model based
Downloads
87
Readme
beta version of fvm for vue3 (composition api) and vue2
Some bugs may still present, please report them
Form Validation Manager - fvm
v2.x.x is compatible with vue2, vue3(options api) and vue3(composition api) v1.x.x is only compatible with vue2
Simple, lightweight model-based validation for Vue.js
Inpired by vuelidate
This plugin usage is similar of vuelidate
Why a new plugin ?
Instead of vuelidate this one allow fine error report and custom messages
and a better integreation in templates
- Model based
- Decoupled from templates
- Minimalistic library
- Support for collection validations
- Support for nested models
- Contextified validators
- Easy to use with custom validators (e.g. Moment.js)
- Easy errors messages customisation
Summary
Installation
npm install form-validation-manager --save
Vue 2 :
Import the library and use as a Vue plugin to enable the functionality globally on all components containing > > validation configuration.
import Vue from 'vue' import Fvm from 'form-validation-manager/vue2' //for typescript import * as fvmTypes from 'form-validation-manager/vue2/types'; import * as fvmTypesValidators from 'form-validation-manager/validators/types'; Vue.use(Fvm)
Basic usage
Vue2 options-api
import { and, required, numeric, gte, length } from 'form-validation-manager/validators'
export default {
data () {
return {
form:{
name: '',
age: 0
}
}
},
validations: {
form:{
name: and(required(), length(gte(3))),
age: and(required(), numeric(), gte(21))
}
},
methods:{
submit(){
if(this.$fvm.$isValid){
//do something
}
}
}
}
a validation oject is generated with the same tree as 'validations'
//generated object
//$fvm
{
$errors:String[],
$error:Boolean,
$isValid:Boolean,
$invalid:Boolean,
$dirty:Boolean,
$pristine:Boolean,
$pending:Boolean,
validate: ()=>void
form:{
$errors:String[],
$error:Boolean,
$isValid:Boolean,
$invalid:Boolean,
$dirty:Boolean,
$pristine:Boolean,
$pending:Boolean,
validate: ()=>void
name:{
$errors:String[],
$error:Boolean,
[...]
},
age:{
$errors:String[],
$error:Boolean,
[...]
}
}
}
- $errors :
- string[]
- For each 'non-final' node : $errors Array concatenate $errors of sub nodes
- $error : node (or sub nodes) has one or more errors
- $isvalid : node (or sub nodes) as no errors
- $invalid : node (or sub nodes) has one or more errors
- $dirty : node (or sub nodes) have been edited by user
- $pristine : node (or sub nodes) have not been edited by user
- $pending : node (or sub nodes) wait for an async validation result
- _validate : force validation of node (and sub nodes)
Vue3 options-api
import { and, required, numeric, gte, length } from 'form-validation-manager/validators'
import { useFvm } from 'form-validation-manager/vue3'
export default {
data () {
return {
form:{
name: '',
age: 0
}
}
},
validations: {
form:{
name: and(required(), length(gte(3))),
age: and(required(), numeric(), gte(21))
}
},
setup:()=>({ fvm$: useFvm()})
}
or
import { and, required, numeric, gte, length } from 'form-validation-manager/validators'
import { useFvm } from 'form-validation-manager/vue3'
export default {
data () {
return {
form:{
name: '',
age: 0
}
}
},
setup(){
return{
fvm$ : useFvm({
form:{
name: and(required(), length(gte(3))),
age: and(required(), numeric(), gte(21))
}
})
}
}
}
validation state is accessible with fvm$
or this.fvm$
Vue3 Composition API
import { and, required, numeric, gte, length} from 'form-validation-manager/validators'
import { useFvm } from 'form-validation-manager/vue3'
export default {
setup () {
const form = reactive({
name: '',
age: 0
});
const validation = useFvm(form, {
name: and(required(), length(gte(3))),
age: and(required(), numeric(), gte(21))
});
return { validation, form };
}
}
validation state is accessible with validation
Specials nodes
export default {
data () {
return {
form:{
list:[
{id:1, value:15}
{id:2, value:0}
],
parent:{
child: {
property:'value'
}
}
}
}
},
validations: {
form:{
liste:{
$each:{
value:gt(0)
}
},
parent:{
$self: custom(function()=>{ /* ...*/ }), //validate parent obj
child:{
property: regexp(/.../) //validate child's property
}
}
}
}
}
- $each : loop over elements of an array
- $self : allow to validate parent and child nodes
Validators
values validation
// generic validators
required()
eq(value) // equal
// number validators
numeric() // is numeric
gt(min) // greater than >
gte(min) // greather than equal >=
lt(max) // less than <
lte(max) // less than equal <=
between(min,max[,exclude])
// string validators
isString()
regexp(expr:RegExp)
includes(str:String)
isDate(format:String='yyyy-MM-dd') // value must be a string date
email() //is email address
logic
and(...validators) // all validators must be ok
andSequence(...validators) // all validators must be ok, call next validator only if previous one is OK
or(...validators) // minimum one validtor must be ok
xor(...validators) // only one validator must be ok
_if(condition:(value,context)=>Boolean, thenValidator[, elseValidator])// apply thenValidator only if condition function returned value is true else apply elsevalidator if defined
not(validator) // validator must be KO
optional(validator) //execute validator only if value != null, undefined or ""
specials
pick(property, validator) // validate value[property] instead of value itself
length(validator) // pick length
withMessage(validator,message) // customise validator message
empty() // always ok validator
custom((value, context)=>Boolean|String|String[]) // allow user to create custom validators
async((value, context)=>Promise<Boolean|String|String[]>, forceRenderUpdateAuto=true, debounceTime=0) // allow user to create custom async validators
revalidate(...paths) // force properties revalidation if this one change
// exmple with previous code : revalidate('form.name')
Arrays
A special node '$each' allow to validate each elements of an array
export default {
data () {
return {
form:{
list : [-1, 5, 10]
}
}
},
validations: {
form:{
list:{
$each : {
and(
gt(0),
custom(function(value,context){
// custom validation code
})
)
}
}
}
}
}
Note : using custom validator under
$each
:context.indexes
contain $each loops indexes. Here :{ 0:<possible values : 0,1,2>, list:<possible values : 0,1,2>, length:1 }
for more details about custom validator, see Custom validation
Messages
withMessage wrapper allow to customise error message
export default {
data () {
return {
form:{
age: 0
}
}
},
validations: {
form:{
age: and(
withMessage(
and(required(), numeric()),
'field is required and must be a number'
),
withMessage(
gte(21),
'you must be of age'
)
)
}
}
}
the property '$errors' will contain defined errors messages if field isnt valid.
Custom validation
component method
a custom method can be used as validator.
inside this one, 'this' refer to current component
export default {
data () {
return {
form:{
age: 0
}
}
},
validations: {
form:{
age: custom(function(value, context){ //do not use arrow function if you want to use 'this'
return this.myValidationMethod(value, context);
})
}
},
methods:{
myValidationMethod(value, context){
// ...
}
}
}
myValidationMethod must return false if no error and true|string|string[] if one or more errors occured
context
contain properties:
component
: current component
path
: current property path (form.age
here)
optional indexes
: contain $each
loops indexes, see $each section
Reusable validator
You may want to define a validator and use it in different components
best way is to define it in separate .js file
import { Validator } from 'form-validation-manager/validators';
export default function myValidator(arg1, arg2) {
return new Validator('myValidator', (value:any, context:Context) => {
if( /* test rule 1 KO */){
return 'message 1'
}
if( /* test rule 2 KO */){
return 'message 2'
}
// is valid
return false
});
}
and use it
import myValidator from './my-validator'
export default {
data () {
return {
form:{
age: 0
}
}
},
validations: {
form:{
age: myValidator('val1', 'val2')
}
}
}
Async validation
export default {
data () {
return {
form:{
age: 0
}
}
},
validations: {
form:{
age: async(function(value, context){
return new Promise(resolve=>{
// async stuf
resolve(myValidationResult)
})
}, debounceTime)
}
},
}
- debounceTime: number : in ms, optional, default=0, if > 0 debounce calls
Before submiting form, you must wait for $pending == false.
Exemples :
- In template :
<form>
<!-- -->
<button type="submit" :disabled="$form.$pending || $form.$error" @click="submit()">Send</button>
</form>
Integration with vuetify
export default {
data () {
return {
form:{
age: 0
}
}
},
validations: {
form:{
age: and(
withMessage(
and(required(), numeric()),
'age is required and must be a number'
),
withMessage(
gte(21),
'you must be of age'
)
)
}
}
}
<v-text-field
:rules="$fvm.form.age.$errors"
/>