vuex-module-validatable-state
Simple Vuex module to handle form fields and validations.
You can build a view model for your form, which runs valdations easily. You just provide initial fields and validators to build the module, then map getters/actions to components.
Play in this sandbox.
Usage
Installation
$ npm i vuex-module-validatable-state
Register to core Vuex module
This module provides the function to return Vuex module as default. The function takes arguments:
- Initial field set
- Validators
A. Define directly
; ; ; new Vuex.Store;
B. Register to existing module
; ; ; ; registerstore, "myForm", initialFields, validators;
Map to Components
Provided Getters
Getter name | Returns |
---|---|
GetterTypes.ALL_FIELDS_VALID |
boolean whether all fields don't have error |
GetterTypes.FIELD_VALUES |
All fields as { [fieldName]: value } |
GetterTypes.FIELD_ERRORS |
All errors as { [fieldName]: errorMessage } |
GetterTypes.FIELD_EDITABILITIES |
All editable flags as { [fieldName]: editability } |
GetterTypes.FIELD_DIRTINESSES |
All dirtiness flags as { [fieldName]: dirtiness } |
GetterTypes.ANY_FIELD_CHANGED |
boolean whether all fields are not dirty |
Provided Actions
Import ActionTypes
from the module.
Action name | Runs |
---|---|
ActionTypes.SET_FIELD |
Set value for a field, then runs validation if enabled |
ActionTypes.SET_FIELDS_BULK |
Set values for fields at once, then make all dirtiness flags false |
ActionTypes.RESET_FIELDS |
Reset values on field with initial values |
ActionTypes.ENABLE_VALIDATION |
Enable interactive validation for a specific field, and run validations on this field immediately |
ActionTypes.ENABLE_ALL_VALIDATIONS |
Enable interactive validations for all fields and run all validations immediately |
ActionTypes.VALIDATE_FIELDS |
Validate for each field that is enabled for interactive validation |
ActionTypes.SET_FIELDS_EDITABILITY |
Set editability flag for a field, disabled field is not updated nor validated |
ActionTypes.SET_FIELDS_PRISTINE |
Make all dirtiness flags false |
Validators
You can pass validators when you initialize the module.
Each validator can take all fields values to run validation:
Optionally, can take getters on the store which calls this module:
And you can request "interactive validation" which valites every time dispatch(ActionTypes.SET_FIELD)
is called
Provided Typings
You can import handy type/interface definitions from the module.
The generic T
in below expects fields type like:
getters[GetterTypes.FIELD_VALUES]
returns values with following FieldValues
interface.
See all typings
ValidatorTree<T>
As like ActionTree, MutationTree, you can receive type guards for Validators. By giving your fields' type for Generics, validator can get more guards for each fields:
SetFieldAction<T>
It's the type definition of the payload for dispatching ActionTypes.SET_FIELD
, you can get type guard for your fields by giving Generics.
FieldValidationErrors<T>
Type for getters[GetterTypes.FIELD_ERRORS]
FieldEditabilities<T>
Type for getters[GetterTypes.FIELD_EDITABILITIES]
FieldDirtinesses<T>
Type for getters[GetterTypes.FIELD_DIRTINESSES]
Working Sample
Registering to Vuex Store
const initialField = amount: 0 description: null; const validators = amount: !amount ? "Amount is required" : false amount <= 0 ? "Amount should be greater than 0" : false description: amount > 1000 && !description ? "Description is required if amount is high" : false ; const store = modules: ... ;
Mapping to Component
<template> <form> <div> <label for="amount">Amount (Required, Positive)</label> <input type="number" name="amount" v-model="amount"> <span v-if="errors.amount">{{ errors.amount }}</span> </div> <div> <label for="description">Description (Required if amount is greater than 1000)</label> <textarea name="description" v-model="description"/> <span v-if="errors.description">{{ errors.description }}</span> </div> <button @click.prevent="submit">Validate and Submit</button> </form></template> <script>import { GetterTypes, ActionTypes } from "vuex-module-validatable-state"; export default { name: "App", computed: { amount: { get() { return this.$store.getters[GetterTypes.FIELD_VALUES].amount; }, set(value) { this.$store.dispatch(ActionTypes.SET_FIELD_VALUE, { name: "amount", value }); } }, description: { get() { return this.$store.getters[GetterTypes.FIELD_VALUES].description; }, set(value) { this.$store.dispatch(ActionTypes.SET_FIELD_VALUE, { name: "description", value }); } }, errors() { return this.$store.getters[GetterTypes.FIELD_ERRORS]; } }, methods: { submit() { this.$store.dispatch(ActionTypes.ENABLE_ALL_VALIDATIONS).then(() => { if (this.$store.getters[GetterTypes.ALL_FIELDS_VALID]) { alert("Form is valid, so now submitting!"); this.$store.dispatch(ActionTypes.SET_FIELDS_PRISTINE); } }); } }};</script>