How to tell if a form field is invalid in vue.js

Viewed 8311

I'm developing a Vue application. I would like to know if a form field is in an invalid state. For example, if the field is required, and the user hits submit, but they haven't filled out the field, then the browser's validation should trigger and the field shows in red with a validation message under it. That's what I mean by an invalid state.

I can reference the field with $refs as follows:

<v-text-field 
    ref="myField"
    required
    v-model="value" />
this.$refs['myField'].what?

Is there anything I can do with $refs['myField'] that will tell me if it's in an invalid state or not?

2 Answers

v-text-field has two mixin properties that could be used to determine its validation status: hasError or valid. To check if the field is invalid, you could do:

this.$refs['myField'].hasError

new Vue({
  el: '#app',
  vuetify: new Vuetify(),
  data () {
    return {
      password: 'Password',
      rules: {
        required: value => !!value || 'Required.',
        min: v => v.length >= 8 || 'Min 8 characters',
      },
    }
  },
})
<script src="https://unpkg.com/vue@2.6.11/dist/vue.min.js"></script>
<script src="https://unpkg.com/vuetify@2.2.28/dist/vuetify.js"></script>
<link rel="stylesheet" href="https://unpkg.com/vuetify@2.2.28/dist/vuetify.min.css">
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">

<v-app id="app">
  <v-container>
    <v-text-field
      ref="password"
      v-model="password"
      :rules="[rules.required, rules.min]"
      type="password"
      label="Password"
      hint="At least 8 characters"
      counter
    ></v-text-field>
    <pre v-if="$refs.password">
      hasError: {{$refs.password.hasError}}
      valid: {{$refs.password.valid}}
    </pre>
  </v-container>
</v-app>

You can use v-model binding on v-form element to get form valid state.

If you can't do that you can bind ref to v-form and probably access valid state internally

Take a look at below snippet!

Vue.config.productionTip = false;
Vue.config.devtools = false;

new Vue({
  el: '#app',
  data: () => ({
    valid: false,
    name: '',
    nameRules: [
      (v) => !!v || 'Name is required',
      (v) => v.length <= 10 || 'Name must be less than 10 characters'
    ],
  }),
  computed: {
    formState() {

      let nameValid = false;
      let errorBucket = []
      let nameInput = this.$refs.nameInput;

      if (nameInput) {
        nameValid = nameInput.valid
        errorBucket = nameInput.errorBucket
      }

      return JSON.stringify({
        valid: this.valid,
        nameValid,
        errorBucket,
        name: this.name
      });
    }
  },
  methods: {
    submit() {
      console.log(this.valid, this.name)
    }
  },
  vuetify: new Vuetify(),
})
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/@mdi/font@4.x/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/vue@2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.js"></script>


<div id="app">
  <v-app>
    <v-content>
      <v-form v-model="valid">
        <v-container>
          <v-text-field ref="nameInput" v-model="name" :rules="nameRules" label="Name"></v-text-field>
          <v-btn :disabled="!valid" class="mr-4" @click="submit">submit</v-btn>
          <div>{{formState}}</div>
        </v-container>
      </v-form>
    </v-content>
  </v-app>
</div>

Related