Search code examples
vuejs3vuelidate

Can't validate email with Vuelidate in Vue3


I'm trying to use validation option in a form. The app is developing under Vue3. I have installed npm install @vuelidate/core @vuelidate/validator into project folder. In a file main.js I have been trying to add Vuelidate as following:

import { createApp } from 'vue'
import Vuelidate from 'vuelidate'
import App from './App.vue'
import './registerServiceWorker'
import router from './router'
import store from './store'
import 'materialize-css/dist/js/materialize.min'
createApp(App).use(store).use(router).use(Vuelidate).mount('#app')

Next I am working on Login.vue file as following

<template>
    <form class="card auth-card" @submit.prevent="onSubmit">
    <div class="card-content">
        <span class="card-title">Example</span>
        <div class="input-field">
        <input
            id="email"
            type="text"
            v-model.trim="email"
            :class="{invalid: ($v.email.$dirty && !$v.email.required) || ($v.email.$dirty && !$v.email.email)}"
        >
        <label for="email">Email</label>
        <small class="helper-text invalid"
        v-if="$v.email.$dirty && !$v.email.required"
        >Could not be empty</small>
        <small class="helper-text invalid"
        v-else-if="$v.email.$dirty && !$v.email.email"
        >Incorrect form</small>
        </div>
    </div>
    <div class="card-action">
        <div>
        <button
            class="btn waves-effect waves-light auth-submit"
            type="submit">
             Enter-login
            <i class="material-icons right">send</i>
        </button>
        </div>
    </div>
    </form>
</template>

<script>
import { email, required, minLength } from '@vuelidate/validators'
import useVuelidate from '@vuelidate/core'

export default {
  name: 'login',
  setup () {
    return { v$: useVuelidate() }
  },
  data: () => ({
    email: '',
    password: ''
  }),
  validations: {
    email: { email, required },
    password: { required, minLength: minLength(6) } 
  },
  methods: {
    onSubmit () {
      if (this.$v.$invalid) {
        this.$v.$touch()
        return
      }
      this.$router.push('/') 
    }
  }
}
</script>

Then I try to run all that with npm run serve but with no success. Chrome DeveloperTools inform me about "Uncaught (in promise) TypeError: Cannot read property 'super' of undefined".

What did I do wrong? Is it possible to use Vue3 and Vuelidate together?

Lidia


Solution

  • Step 1: Import useVuelidate inside component

    import useVuelidate from "@vuelidate/core";
    import { email, required, minLength } from "@vuelidate/validators";
    

    Step 2: Initalize useVuelidate inside component

    setup() {
        return { v$: useVuelidate() };
    },
    

    Step 3: Initalize your modal data

    data() {
        return {
          email: '',
          password: ''
        };
    },
    

    Step 4: Add validations rule

    validations() {
        return {
          email: { email, required },
          password: { required, minLength: minLength(6) }
        };
    },
    

    Step 5: Add form submit method

    methods: {
      onSubmit: function() {
        this.v$.$touch();
        if (this.v$.$error) return;
        alert('Form is valid')
      }
    }
    

    Step 6: HTML template design will be like,

    <form class="card auth-card" @submit.prevent="onSubmit">
        <div class="card-content">
          <span class="card-title">Example</span>
          <div class="input-field">
            <label for="email">Email <span class="required">*</span></label>
            <input id="email" type="text" v-model.trim="email">
            <small class="error" v-for="(error, index) of v$.email.$errors" :key="index">
              {{ capitalizeFirstLetter(error.$property) }} {{error.$message}}
            </small>
          </div>
          <div class="input-field">
            <label for="email">Password <span class="required">*</span></label>
            <input id="email" type="text" v-model.trim="password">
            <small class="error" v-for="(error, index) of v$.password.$errors" :key="index">
              {{ capitalizeFirstLetter(error.$property) }} {{error.$message}}
            </small>
          </div>
        </div>
        <div class="card-action">
          <div>
            <button class="btn waves-effect waves-light auth-submit" type="submit"> Enter-login<i class="material-icons right">send</i>
            </button>
          </div>
        </div>
      </form>
    </template>
    

    DEMO