Search code examples
javascriptvue.jsvuelidate

Vue.js - Vuelidate custom validator


I am using vuelidate, and need to do some custom validation but it involve taking into consideration different fields. For example: I have a radio button to select between Month and Year

If I select Month I will have a Year Start (2021, 2020,...) and Month Start (1, 2, 3...) dropdown and a Year End and Month End dropdown.

If I select Year I will have a Year Start (2021, 2020,...) and Year End (2021, 2020,...) dropdown.

My problem is that I need to validate for month option that year start is bigger than year end or that they can be equal and month start must be greater than month end.

And for year option Year start should be greater than Year End

I have this:

validations() {
  return {
    form: {
      startMonth: {},
      startYear: { required },
      endMonth: {},
      endYear: { required },
    }
  };
}

This is the logic I want to turn into a custom validator

if (this.option === "Year") {
  if (this.startYear > this.endYear) {
    return true;
  } else {
    return false;
  }
}

else if (this.option === "Month") {
  if (this.startYear > this.endYear) {
    return true;
  } else if (this.startYear == this.endYear && parseInt(this.startMonth) > parseInt(this.endMonth)) {
    return true;
  } else {
    return false;
  }
}

Any insight, help would be highly appreciated.

UPDATE Possible Solution:

<script>
import { validationMixin } from 'vuelidate';
import { required } from 'vuelidate/lib/validators';
  data() {
    return {
      form: {
        month: null,
        year: null,
        compareMonth: null,
        compareYear: null
      },
    };
  },
  computed: {
    disableApply() {
      return this.$v.form.$invalid;
    },
  },

  methods: {
    validateYear() {
      if (this.$v.form.year.$model > this.$v.form.compareYear.$model) {
        return true;
      } else {
        return false;
      }
    },

    validateMonth() {
      if (this.validateYear()) {
        return true;
      } 

      if (this.$v.form.year.$model === this.$v.form.compareYear.$model && parseInt(this.$v.form.month.$model) > parseInt(this.$v.form.compareMonth.$model)) {
        return true;
      } else {
        return false;
      }
    }
  },

  validations() {
    return {
      form: {
        month: { required, validateMonth: this.validateMonth },
        year: { required, validateMonth: this.validateYear },
        compareMonth: { required, validateMonth: this.validateMonth },
        compareYear: { required, validateMonth: this.validateYear },
      }
    };
  }
};
</script>

Solution

  • According to accessing-component you can directly access the component instance using this keyword.
    Try converting your code into Vue instance methods like

    function validateYear() {
      if (this.startYear > this.endYear) {
        return true;
      } else {
        return false;
      }
    }
    
    function validateMonth() {
      if (this.validateYear()) {
        return true;
      }
      if (this.startYear == this.endYear && parseInt(this.startMonth) > parseInt(this.endMonth)) {
        return true;
      } else {
        return false;
      }
    }
    

    and then apply them as custom validators:

    validations() {
      return {
        form: {
          startMonth: {
            validateMonth: this.validateMonth
          },
          startYear: { 
            required,
            validateMonth: this.validateYear
          },
          endMonth: {
             validateMonth: this.validateMonth
          },
          endYear: { 
            required,
            validateMonth: this.validateYear
          },
        }
      };
    }
    

    P.S this could probably be optimised better using passed in value, this.$v values, ternary expressions etc, I just want to give you an idea to move forward