2.3.0 • Published 1 year ago

form-validation-manager v2.3.0

Weekly downloads
-
License
LGPL3
Repository
-
Last release
1 year ago

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

Test Coverage Dependencies Typescript LGPL3

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"
/>
2.3.0-beta.1

1 year ago

2.3.0-beta.4

1 year ago

2.3.0-beta.5

1 year ago

2.3.0-beta.2

1 year ago

2.3.0-beta.3

1 year ago

2.3.0

1 year ago

2.2.1

1 year ago

2.0.3

1 year ago

2.2.0

1 year ago

2.2.3

1 year ago

2.0.5

1 year ago

2.2.2

1 year ago

2.0.4

1 year ago

2.2.5

1 year ago

2.2.4

1 year ago

2.2.7

1 year ago

2.2.6

1 year ago

2.0.1

1 year ago

2.0.0

1 year ago

2.1.1

1 year ago

2.1.0

1 year ago

2.2.8

1 year ago

1.11.3

2 years ago

1.11.0

2 years ago

1.11.2

2 years ago

1.11.1

2 years ago

1.10.3

2 years ago

1.10.2

2 years ago

1.10.1

2 years ago

1.10.0

2 years ago

1.9.1

3 years ago

1.9.0

3 years ago

1.8.2

3 years ago

1.8.1

3 years ago

1.8.0

3 years ago

1.7.6

3 years ago

1.7.4

3 years ago

1.7.3

3 years ago

1.7.2

3 years ago

1.7.1

3 years ago

1.7.0

4 years ago

1.5.5

4 years ago

1.6.0

4 years ago

1.5.4

4 years ago

1.5.3

4 years ago

1.5.2

4 years ago

1.5.1

4 years ago

1.5.0

4 years ago

1.4.2

4 years ago

1.4.1

4 years ago

1.4.0

4 years ago

1.3.0

4 years ago

1.2.9

4 years ago

1.2.10

4 years ago

1.2.8

4 years ago

1.2.7

4 years ago

1.2.6

4 years ago

1.2.5

4 years ago

1.2.4

4 years ago

1.2.3

4 years ago

1.2.2

4 years ago

1.2.1

4 years ago

1.2.0

4 years ago

1.1.0

4 years ago

1.0.8

4 years ago

1.0.7

4 years ago

1.0.6

4 years ago

1.0.4

4 years ago

1.0.3

4 years ago

1.0.2

4 years ago