vuelidate: Vue 3 + vuelidate@next: $v.$error remains false

I’m using Vue 3 and Vuelidate@next and while $v.$invalid works $v.$error and $v.$dirty always remain false even though the individual validators show true (i.e. $v.password.$error returns true).

Sorry, couldn’t figure out how to create a jsFiddle with vuelidate@next, but here is my relevant html and js:

  <input v-model.trim="$v.email.$model"/>
  <input v-model.trim="$v.password.$model"/>

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

Here is my full vue component if needed:

<template>
<div>
  <h2 class="header">Sign In</h2>
  $v.$error: {{$v.$error}}<br/>
  $v.$invalid: {{$v.$invalid}}<br/>
  $v.$dirty: {{$v.$dirty}}<br/>
  $v.$anyError: {{$v.$anyError}}<br/>
  $v.$anyInvalid: {{$v.$anyError}}<br/>
  $v.$anyDirty: {{$v.$anyDirty}}<br/>
   $v.password.$error: {{ $v.password.$error }}<br/>
  <form @submit="signIn" autocomplete="off" novalidate>
    <div class="form-group" :class="{ 'error' : $v.email.$error }">
      <label for="email">Email:</label>
      <!-- <em v-if="$v.email.$error && $v.email.email.$invalid">Invalid Email</em> -->
      <em v-if="$v.email.$error && $v.email.required.$invalid">Required</em>
      <input v-model.trim="$v.email.$model"/>
    </div>
    <div class="form-group" :class="{ 'error' : $v.password.$error }">
      <label for="password">Password:</label>
      <em v-if="$v.password.$error">Required</em>
      <input v-model.trim="$v.password.$model"/>
    </div>
    <div class="form-group buttons" >
      <button type="button" @click="cancel()">Cancel</button>
      <button class="save" type="submit" :disabled="$v.$errors.length > 0">
        Sign In
      </button>
    </div>
  </form>
</div>
</template>

<script>
import { required } from '@vuelidate/validators';

export default {
  name: 'SignIn',
  data() {
    return {
      email: '',
      password: '',
    };
  },
  validations: {
    email: { required },
    password: { required },
  },
  methods: {
    signIn(credentials) {
      this.userRepository.signIn(credentials)
        .subscribe(
          null,
          (err) => { console.$error(err, 'Error'); },
          () => this.router.navigate(['/catalog']),
        );
    },
    cancel() {
      this.router.navigate(['/']);
    },
  },
};

</script>

<style scoped>
form {
  color: #336699;
  font-size:18px;
  padding:30px;
  width: 298px;
  margin: 0 auto;
}
input {
  display: block;
  font-size:18px;
  padding-left:10px;
  width: 275px;
}
button {
  font-size: 24px;
  color: #336699;
}
button:disabled {
  color: #999999;
}
.header {
  color: #336699;
  text-align:center;
  padding-top:20px;
  margin-top:0;
}
.form-group {
  margin: 10px;
}
.buttons {
  text-align: right;
  margin-right: 0px;
}
.save {
  background-color: #CCDDFF;
  border-color: #CCDDFF;
}
em {float:right; color:#E05C65; padding-left:10px;}
.$error input, .$error select, .$error textarea {background-color:#E3C3C5;}
.$error ::-webkit-input-placeholder { color: #999; }
.$error :-moz-placeholder { color: #999; }
.$error ::-moz-placeholder { color: #999; }
.$error :ms-input-placeholder  { color: #999; }
</style>


About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 15 (9 by maintainers)

Most upvoted comments

Following on from what @MauroB45 has said, I agree that $invalid only being evaluated when $dirty is true is a big change, and it makes it hard to do some things that the previous implementation made very easy.

For example, many of our forms will have the Submit button disabled while any form field is $invalid. We display a red outline on form fields that have $error = true, but not on form fields that have $invalid = true. That way a form can be $invalid on load, disabling the submit button, but the user will only see a red outline on fields they’ve interacted with. This gives the user the opportunity to attempt filling out the entire form, and they only get negative feedback after they’ve interacted with a form field, but left it in an invalid state.

I don’t disagree with evaluation being lazy, but perhaps there should be an option to trigger evaluation when validation is first set up, that doesn’t mark fields as $dirty. Alternatively, perhaps giving an option to trigger validation manually without marking the validation dirty would also suffice?

I have a Todo in the src we should fix this hehe

Yup! This is something I’ve been thinking about. Having the validators lazy by default is pretty cool, but it definitely needs a way to be evaluated without being dirty. @dobromir-hristov whats your take here? I will probably work on that during the weekend.

Might also reverse it somewhat so that initial evaluation is the default behavior and the user is able to make it lazy through config. @aethr

For me, the $invalid property being lazy by default is a big change. In my case, I am using the $invalid prior to any user interaction to control the state of a form “section” to remain in edit/display mode. If the section validation branch was invalid I would not close (set as display mode) the specific section. If valid It could be closed automatically and if $anyError was true then I would display error feedback to the user. I could manage this by keeping track of interactions or initial validations myself, but it was nice to be able to check the $invalid state for this.

If $invalid will be evaluated if the field is $dirty then is it any different of $error? I might be missing something.

Related to this, if I’m understanding the docs right, I think the following are also bugs with this version:

  • $v.$anyError is missing
  • $v.$anyInvalid is missing
  • $v.$invalid is false if there is an invalid field that is not dirty