Search code examples
vue.jsvuelidate

How to map a nested Vuelidate validation object with computed properties in VueJS?


I have a tabs container with multiple forms. Some of the fields in all forms have some complex logic that I didn't want to repeat on each form, so I created a custom component that is used in all forms. I'm trying to use Vuelidate to validate all of my forms but since those field names are the same, and of course have the same validation logic, the Vuelidate validation object is the same in all forms, meaning, if I fill in the email field in formA, then all forms with that same field will also validate correctly, even though the rest of the forms haven't been filled in at all.

I tried to wrap my validations inside an object named as the forms, and this seems to separate all validation logic correctly, but, I have other setup there that prevents me from using data attributes and I use computed attributes instead. As far as I know, the validations object must match the way we access fields data, like, data() { formA: { email } } would match to validation object validations: { formA: { email } }, the problem is, since I'm not using data properties, I don't know how to map computed properties.

This is what I have:

  export default {
    components: { PhoneField, TopNote, SubmitButton, NameFieldsGroup, EmailField },
    validations: {
      formA: {
        firstName: { required },
        lastName: { required },
        email: {
          required,
          email
        },
        phone: {
          required,
          length: minLength(10)
        }
      }
    },
    created() {
      this.$store.commit('setFormValidation', this.$v);
    },
    data() {
      return {}
    },
    computed: {
      firstName: function() {
        return this.$store.getters.formState.firstName;
      },
      lastName: function() {
        return this.$store.getters.formState.lastName;
      },
      email: function() {
        return this.$store.getters.formState.email;
      },
      phone: function() {
        return this.$store.getters.formState.phone;
      }
    }
  };

I've been messing around with this for the past several days, but can't figure it out. Anyone can suggest a solution for this?


Solution

  • Figured it out. Not sure why it works but it does now. The fix is to use Vuex's mapState like this:

    import { mapState } from 'vuex';
    
    export default {
        components: { PhoneField, TopNote, SubmitButton, NameFieldsGroup, EmailField },
        validations: {
          formA: {
            firstName: { required },
            lastName: { required },
            email: {
              required,
              email
            },
            phone: {
              required,
              length: minLength(10)
            }
          }
        },
        created() {
          this.$store.commit('setFormValidation', this.$v);
        },
        data() {
          return {}
        },
        computed: {
          ...mapState(['formA']),
          firstName: function() {
            return this.$store.getters.formState.firstName;
          },
          lastName: function() {
            return this.$store.getters.formState.lastName;
          },
          email: function() {
            return this.$store.getters.formState.email;
          },
          phone: function() {
            return this.$store.getters.formState.phone;
          }
        }
      };