How to validate Vuetify text field asynchronously?

2020-06-20 05:28发布

Text fields in Vuetify have rules props, which take an array of functions returning true or an error string. How to make them async, so that the validation could be made server-side using XHR?

Something like:

<v-text-field :rules="[v => { axios.get('/check?value=' + val).then(() => { return true }) }]">

2条回答
Evening l夕情丶
2楼-- · 2020-06-20 05:38

One solution is to set the error-messages prop:

<v-text-field v-model="input" :error-messages="errors">

and use the watch method:

new Vue({
  data () {
    return {
      input: '',
      errors: []
    }
  },
  watch: {
    input (val) {
        axios.get('/check?value=' + val).then(valid => {
          this.errors = valid ? [] : ['async error']
        })
    }
  }
});
查看更多
做个烂人
3楼-- · 2020-06-20 05:50

I have to do a backend validation to check if the username entered already exists. I use the swagger client library with the JSON open API v3 to call the method that checks the username value.

So I solved in this way...

In my login.js file I have defined a string property that contains the error message:

import swaggerClient from "../remote-client";
const strict = true;
const state = {
  hasError: false,
  error: null,
  usernameAlredyExists: ""
};
const getters = {
  hasError: state => state.hasError,
  error: state => state.error,
  usernameAlredyExists: state => state.usernameAlredyExists
};
const mutations = {
  checkingUsername(state) {
    state.hasError = false;
    state.error = null;
    state.usernameAlredyExists = "";
  },
  usernameCheckedKO(state) {
    state.usernameAlredyExists = "Username already exists";
  },
  usernameCheckedOK(state) {
    state.usernameAlredyExists = "";
  },
  errorCheckingUsername(state, error) {
    state.hasError = true;
    state.error = error;
  },
};
const actions = {
  userLogin({ commit }, { username, password }) {
    // not relevant code
  },
  checkUsername({ commit }, { username }) {
    commit("checkingUsername");
    swaggerClient.userSwaggerClient
      .then(
        function(client) {
          return client.apis.UserHealthFacility.getHfUserUsernameWithUsername(
            { username: username },
            {},
            {}
          );
        },
        function(reason) {
          // failed to load the JSON specification
          commit("errorCheckingUsername", reason);
        }
      )
      .then(
        function(callResult) {
          if (callResult.body) {
            commit("usernameCheckedKO");
          } else {
            commit("usernameCheckedOK");
          }
        },
        function(reason) {
          // failed to call the API method
          commit("errorCheckingUsername", reason);
        }
      );
  }
};

export default {
  namespaced: true,
  strict,
  state,
  getters,
  mutations,
  actions
};

Then in the Login.vue file I have this code:

<v-card-text>
  <v-form ref="loginForm" v-model="loginValid" lazy-validation>
    <v-text-field
      v-model="username"
      label="Username"
      :rules="[rules.required]"
      :error-messages="usernameAlredyExists"
      v-on:change="callCheckUsername"
    ></v-text-field>
    <v-text-field
      v-model="password"
      :label="Password"
      :append-icon="showPassword ? 'visibility_off' : 'visibility'"
      :type="showPassword ? 'text' : 'password'"
      :rules="[rules.required, rules.minLength]"
      counter
      @click:append="showPassword = !showPassword"
    ></v-text-field>
  </v-form>
</v-card-text>
<v-card-actions>
  <v-spacer></v-spacer>
  <v-btn
    :disabled="!loginValid"
    @click="callUserLogin"
    color="primary"
    round
  >Login</v-btn>
</v-card-actions>

<script>
export default {
  data() {
    return {
      username: "",
      password: "",
      showPassword: false,
      loginValid: true,
      rules: {
        required: value => !!value || "Questo campo è obbligatorio",
        minLength: value =>
          value.length >= 8 || "Questo campo deve contenere almeno 8 caratteri"
      }
    };
  },
  computed: {
    usernameAlredyExists() {
      return this.$store.getters["login/usernameAlredyExists"];
    }
  },
  methods: {
    callUserLogin() {
      if (this.$refs.loginForm.validate()) {
        this.$store.dispatch("login/userLogin", {
          username: this.username,
          password: this.password
        });
      }
    },
    callCheckUsername(value) {
      if (value) {
        this.$store.dispatch("login/checkUsername", {
          username: this.username
        });
      }
    }
  }
};
</script>

In this way it seems to work well

查看更多
登录 后发表回答