Search code examples
javascriptvue.jsvuejs2vuexvuelidate

Proper way to use Vuex with Vuelidation


I'm working on a Vue front end for an application that requires all form data be persisted locally before submitting to the backend in case a network connection issue causes an interruption of service. I'm using Vuex to maintain all the form data across the application, so that it can be persisted and restored to/from local storage as required.

A second requirement is form validation, for which I intend to use the Vuelidate library. The documentation suggests that to use Vuelidate without a v-model, all that is required is this.$v.touch() in the event function. That is what I have tried, but it does not seem to work.

See the example below:

<template>
  <form>
    <input name="full-name" v-model="fullName" placeholder="Full Name" />
  </form>
</template>

<script>
  export default {
    name: "AForm"
    computed: {
      fullName: {
        get() { return this.$store.state.fullName }
        set(name) {
          this.$v.touch();
          this.$store.dispatch("updateFullName", name);
        },
      }
    },
    validations: {
      fullName: minLength(4);
    }
  }
</script>

When I examine $v.fullName, the value is just equal to true. When I look at the entire $v object, I see $anyDirty: false.

Codesandbox


Solution

  • Validation config malformed

    The validation config should be:

    export default {
      /**
       * Validation Config Format:
       *
       *   validations: {
       *     PROP_NAME: {
       *       RULE_NAME: RULE
       *     }
       *   }
       */
      validations: {
        //fullName: minLength(4), // DON'T DO THIS
    
        fullName: {
          minLength: minLength(4)
        }
      },
    }
    

    $touch

    It looks like you used this.$v.touch(), but it's supposed to be this.$v.$touch(). However, since the computed prop sets only one prop, you should just invoke $touch() on that prop (i.e., $v.PROP_NAME.$touch()) after the prop is changed through the Vuex action.

    export default {
      computed: {
        fullName: {
          get() {
            return this.$store.state.fullName;
          },
          set(name) {
            //this.$v.touch() // DON'T DO THIS
    
            this.$store.dispatch('updateFullName', name)
            this.$v.fullName.$touch()
          }
        }
      }
    }
    

    Edit Using Vuelidate with Vuex