Search code examples
vue.jsvuejs3vuelidate

Validate a form before submit in Vue3 composition api with vuelidate


According to documentation example there is the following Vue.js options api way to validate the whole form before submitting it

export default {
  methods: {
    async submitForm () {
      const isFormCorrect = await this.v$.$validate()
      // you can show some extra alert to the user or just leave the each field to show it's `$errors`.
      if (!isFormCorrect) return
      // actually submit form
    }
  }
}

I am using Vue.js 3 with composition api and simply can't make this work in my case.

In my <template> i have a form

<form
  @submit="submitHandler"
>
  <input>
    :error="v$.productName.$invalid && v$.productName.$dirty"
    @input="v$.productName.$touch()"
  </input>
  
  <input>
    :error="v$.productPrice.$invalid && v$.productPrice.$dirty"
    @update:model-value="v$.productPrice.$touch()"
  </input>

  ...
</form>

Under <script setup> tag i have the following

import { useVuelidate } from '@vuelidate/core'
import { required, integer, minValue } from '@vuelidate/validators'
...
const state = reactive({
  productName: '',
  productPrice: '',
  
  ...
})

const rules = {
  productName: { required, $lazy: true },
  productPrice: { required, integer, minValue: minValue(1), $lazy: true },
  
  ...
  $validationGroups: {
    allProductData: [
      'productName',
      'productPrice' ,
      
      ...
    ]
  }
}

const v$ = useVuelidate(rules, state)

...

const submitHandler = async () => {
  try {
    const isFormCorrect = await v$.$validate()
    console.log('Submit Fired')
  } catch (error) {
    console.warn({error})
  }
}

submitHandler() gives me an error saying error: TypeError: v$.$validate is not a function. I tried with and without making it async and got the same error. I also tried to place the same code directly in the <form> @click event handler and it works perfectly fine.

<form
  @submit="v$.validate()"
>
...
</form>

Am i missing something ? It seems to me like vuelidate2 v$.methodName() only works in the template which is strange because i recall using it exactly as documentation suggests in my Vue.js 2 applications


Solution

  • useVuelidate returns a ref, this is not well-documented but can be expected from a reactive composable.

    Refs are automatically unwrapped in a template, in a script it's supposed to be:

    const isFormCorrect = await unref(v$).$validate()