Vuelidate: validate on click, not when field touched
Asked Answered
C

4

20

I'm kinda new to vuelidate, and everything works fine, except I have no clue how to run validation only when the button Submit has been clicked. Right now it marks touched field red when you start providing any input and I'd like it to wait with that, till user wants to submit filled form.

Here's what I've got up to now:

Vue.use(window.vuelidate.default)
const { required, minLength, sameAs } = window.validators

new Vue({
	el: "#app",
  data: {
  	user: {
    	login: '',
      password: '',
      repeatedPassword: ''
    }
  },
  validations: {
  	user: {
    	login: {
      	required,
        minLength: minLength(5)
      },
      password: {
    	  required,
        minLength: minLength(8)
      },
      repeatedPassword: {
      	required,
        sameAs: sameAs('password')
      }
    }
  }
})
input {
  border: 1px solid silver;
  border-radius: 4px;
  background: white;
  padding: 5px 10px;
}

.error {
  border-color: red;
  background: #FDD;
}

.error:focus {
  outline-color: #F99;
}

.valid {
  border-color: #5A5;
  background: #EFE;
}

.valid:focus {
  outline-color: #8E8;
}
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/vuelidate/dist/validators.min.js"></script>
<script src="https://unpkg.com/vuelidate/dist/vuelidate.min.js"></script>
`<div id="app">

  <input type="text" placeholder="login"
    v-model="user.login"
    v-on:input="$v.user.login.$touch"
    v-bind:class="{error: $v.user.login.$error, valid: $v.user.login.$dirty && !$v.user.login.$invalid}">
  <br/>    
  <input type="password" placeholder="password"
    v-model="user.password"
    v-on:input="$v.user.password.$touch"
    v-bind:class="{error: $v.user.password.$error, valid: $v.user.password.$dirty && !$v.user.password.$invalid}">
  <br/>  
  <input type="password" placeholder="repeat password"
    v-model="user.repeatedPassword"
    v-on:input="$v.user.repeatedPassword.$touch"
    v-bind:class="{error: $v.user.repeatedPassword.$error, valid: $v.user.repeatedPassword.$dirty && !$v.user.repeatedPassword.$invalid}"
  >
  <button :disabled="$v.user.$error" @click="$v.user.$touch()">
    Submit!
  </button>
</div>`
Canonicity answered 31/8, 2017 at 14:35 Comment(0)
M
4

I could never really get used to the Vuelidate way of doing things, but, generally speaking, it works like this: https://monterail.github.io/vuelidate/#sub-basic-form

Setting it up like this allows you to have validation for each form input/element and then an overall check to see if the form is "dirty" and/or "invalid"

form: {
"name": {
"required": false,
"$invalid": true,
"$dirty": false,
"$error": false,
"$pending": false,
"$params": {
  "required": {
    "type": "required"
  }
}
},
"Age": {
  "required": false,
  "$invalid": true,
  "$dirty": false,
  "$error": false,
  "$pending": false,
  "$params": {
    "required": {
      "type": "required"
    }
  }
},
"$invalid": true,  <------- This is what you are after for valid/invalid
"$dirty": false,   <------- This is what you are after to see if the form has been used.
"$error": false,  <-------  This checks both invalid and dirty
"$pending": false,
"$params": {
   "nestedA": null,
   "nestedB": null
}
}

As far as using this in practice, one option would be to call validateform event on submit.

@click.prevent="validateform"

Then create a validateform method in your vue instance that checks

$v.form.$invalid  or $v.form.$error

then either display errors or call the actual submit method

Mortality answered 31/8, 2017 at 17:12 Comment(1)
The context is still helpful, but the link is 404Compost
N
4

Then the only thing you have to do after setting up the validations is to call a method that will validate the errors. So follow below:

<button @click="validate">Submit</button>

The method:

validate () {
  this.$v.$touch() //it will validate all fields
  if (!this.$v.$invalid) { //invalid, becomes true when a validations return false
   //you dont have validation error.So do what u want to do here
  }
}
Nicolnicola answered 8/3, 2018 at 21:2 Comment(0)
C
0

Right now it marks touched field red when you start providing any input

That means the field is getting "dirty" automatically but as the last version (Vuelidate 2) that is not the default behavior.

Please check if you have $autoDirty: true and remove it or set it to "false"

To do what you need using Vuelidate 2, you only need to call $touch() on the submit click event as $autoDirty is false by default. Check Roland's answer.

Courtier answered 26/1, 2023 at 15:57 Comment(0)
E
-2

Here is what I do with VeeValidate 3:

<validation-observer ref="jobValidation">
 <form>
     <button v-on:click="nextPage()" type="button">Next</button>
 </form>
</validation-observer>

and within methods:

nextPage(): void {                 
    const validation = (this.$refs.jobValidation as any);
    validation.validate().then(() => {                 
    if (validation.flags.invalid) {                           
        // No no no no
        // bonus: show all errors in summary
        validation.$children.forEach((child: any) => {
           child.errors.forEach((error: any) => {
              console.log(error);
           });
           return;
        });
    } else {
        // Yes yes yes
    }
    });  
},
Electrochemistry answered 12/8, 2020 at 20:24 Comment(1)
It's Vuelidate question, no VeeValidateMunicipality

© 2022 - 2024 — McMap. All rights reserved.