Vuejs: vuelidate conditional validation

Viewed 4983

suppose we have a password field and we want to do some validations of length, specialcharacters, numbers, upper case and lower case etc, only if the field has a value

how can we do that with vuelidate.

here I am import vuelidate

import { required, minLength, maxLength, email, sameAs } from 'vuelidate/lib/validators'

Here the validations

validations: {
    editedItem: {
      firstname: { required, minLength: minLength(3), maxLength: maxLength(20) },
      lastname: { required, minLength: minLength(3), maxLength: maxLength(20) },
      email: { required, email },
      password: {
        required,
        minLength: minLength(6),
        maxLength: maxLength(15),
        oneNumber,
        oneUpperCase,
        oneLowerCase,
      },
      repassword: {
        sameAsPassword: sameAs('password'),
      },
    },
  }

,

oneNumber, oneUpperCase and oneLowerCase are custom validations:

const oneNumber = (value) => /[0-9]/.test(value)
const oneUpperCase = (value) => /[A-Z]/.test(value)
const oneLowerCase = (value) => /[a-z]/.test(value)

I will forever appreciate any help or advice

1 Answers

My solution involves a separate "custom validators" file.

validators.js:

import { helpers as vuelidateHelpers } from 'vuelidate/lib/validators'

export const oneUppercase = value => {
  if (!vuelidateHelpers.req(value)) {
    return true
  }
  const match = value.match(/[A-Z]/g) || []
  return match.length >= 1
}
export const oneLowercase = value => {
  if (!vuelidateHelpers.req(value)) {
    return true
  }
  const match = value.match(/[a-z]/g) || []
  return match.length >= 1
}
export const oneSpecial = value => {
  if (!vuelidateHelpers.req(value)) {
    return true
  }
  const match = value.match(/[ !@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]/g) || []
  return match.length >= 1
}
export const oneNumber = value => {
  if (!vuelidateHelpers.req(value)) {
    return true
  }
  const match = value.match(/\d/g) || []
  return match.length >= 1
}

In the component, with visual formatting to let the user know if their password meets the requirement:

<template>
  <form>
    <label for="password">Password</label>
    <input
            id="password"
            name="password"
            type="password"
            v-model="form.password"
            @blur="$v.form.password.$touch()"
            @input="validatePassword"
    />
    <label for="confirmPassword">Confirm Password</label>
    <input
            id="confirmPassword"
            name="confirmPassword"
            type="password"
            v-model="form.confirmPassword"
            @blur="$v.form.confirmPassword.$touch()"
    />
    <ul>
      <li>
          {{
          passwordValidations.eightCharacters ?
          '✓':
          '╳'
          }}
        <span class="ml-1">MUST contain 8 characters</span>
      </li>
      <li>
          {{
          passwordValidations.oneUppercase ?
          '✓':
          '╳'
          }}
        <span class="ml-1">MUST contain one uppercase letter</span>
      </li>
      <li>
          {{
          passwordValidations.oneLowercase ?
          '✓':
          '╳'
          }}
        <span class="ml-1">MUST contain one lowercase letter</span>
      </li>
      <li>
          {{
          passwordValidations.oneNumber ?
          '✓':
          '╳'
          }}
        <span class="ml-1">MUST contain one number</span>
      </li>
      <li>
          {{
          passwordValidations.oneSpecial ?
          '✓':
          '╳'
          }}
        <span class="ml-1">MUST contain one special character</span>
      </li>
    </ul>
  </form>
</template>

<script>
  import {
    required,
    minLength,
    sameAs,
  } from 'vuelidate/lib/validators'
  import {
    oneNumber,
    oneSpecial,
    oneUppercase,
    oneLowercase,
  } from '../validators'

  export default {
    data () {
      return {
        form: {
          password: '',
          confirmPassword: '',
        },
        passwordValidations: {
          eightCharacters: false,
          oneUppercase: false,
          oneLowercase: false,
          oneNumber: false,
          oneSpecial: false,
        },
      }
    },
    computed: {
      passwordErrors () {
        const errors = []
        if (!this.$v.form.password.$dirty) return errors
        !this.$v.form.password.required && errors.push('Password is required.')
        return errors
      },
      confirmPasswordErrors () {
        const errors = []
        if (!this.$v.form.confirmPassword.$dirty) return errors
        !this.$v.form.confirmPassword.required && errors.push('Please confirm your password.')
        !this.$v.form.confirmPassword.sameAsPassword && errors.push('Passwords don\'t match')
        return errors
      },
    },
    methods: {
      validatePassword () {
        this.passwordValidations.eightCharacters = this.$v.form.password.eightCharacters
        this.passwordValidations.oneUppercase = this.$v.form.password.oneUppercase
        this.passwordValidations.oneLowercase = this.$v.form.password.oneLowercase
        this.passwordValidations.oneNumber = this.$v.form.password.oneNumber
        this.passwordValidations.oneSpecial = this.$v.form.password.oneSpecial
      },
    },
    validations: {
      form: {
        password: {
          required,
          minLength: minLength(8),
          oneUppercase,
          oneSpecial,
          oneNumber,
          oneLowercase,
        },
        confirmPassword: {
          required,
          sameAsPassword: sameAs('password'),
        },
      },
    },
  }
</script>
Related