npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

vuex-module-validatable-state

v0.5.0

Published

Simple Vuex module to validate state for handling form

Downloads

12

Readme

vuex-module-validatable-state

npm CircleCI

Simple Vuex module to handle form fields and validations.

190611_module

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
import validatableModule from "vuex-module-validatable-state";

const initialFields = {
  amount: null,
  description: "default text"
};

const validators = {
  amount: [
    ({ amount }) => amount === null ? "Require this" : false
  ],
  description: [
    ({ description }) => description.length > 15 ? "Should be shorter than 15" : false,
    ({ description, amount }) => description.indexOf(amount.toString())  ? "Should include amount" : false,
  ]
};

new Vuex.Store({
  modules: {
    myForm: {
      namespaced: true
      store,
      getters,
      actions,
      mutations,
      modules: {
        ...validatableModule(initialFields, validators) // <-- HERE
      }
    }
  }
});
import { register } from "vuex-module-validatable-state";

const initialFields = {
  amount: null,
  description: "default text"
};

const validators = {
  amount: [
    ({ amount }) => amount === null ? "Require this" : false
  ],
  description: [
    ({ description }) => description.length > 15 ? "Should be shorter than 15" : false,
    ({ description, amount }) => description.indexOf(amount.toString())  ? "Should include amount" : false,
  ]
};

const store = new Vuex.Store({
  modules: {
    myForm: {
      namespaced: true
      store,
      getters,
      actions,
      mutations
    }
  }
});

register(store, "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.

const validators = {
  amount: [/* validators for filling error against to amount */],
  description: [/* validators for filling error against to description */]
}

Each validator can take all fields values to run validation:

const validators = {
  amount: [
    ({ amount, description }) => /* return false or errorMessage */
  ]
}

Optionally, can take getters on the store which calls this module:

const validators = {
  description: [
    ({ description }, getters) => getters.getterOnStore && validationLogicIfGetterOnStoreIsTruthy(description)
  ]
}

And you can request "interactive validation" which valites every time dispatch(ActionTypes.SET_FIELD) is called

const validators = {
  amount: [
    [({ amount }, getters) => /* validator logic */, { instant: true }]
  ]
}

Provided Typings

You can import handy type/interface definitions from the module. The generic T in below expects fields type like:

interface FieldValues {
  amount: number;
  description: string;
}

getters[GetterTypes.FIELD_VALUES] returns values with following FieldValues interface.

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:

image

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.

image

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

Edit Sample: vuex-module-validatable-state

Registering to Vuex Store

const initialField = {
  amount: 0,
  description: null
};

const validators = {
  amount: [
    ({ amount }) => (!amount ? "Amount is required" : false),
    ({ amount }) => (amount <= 0 ? "Amount should be greater than 0" : false)
  ],
  description: [
    ({ amount, description }) =>
      amount > 1000 && !description
        ? "Description is required if amount is high"
        : false
  ]
};

const store = new Vuex.Store({
  modules: {
    ...theModule(initialField, validators)
  }
});

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>