Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vue.js vuelidate: How to debounce async custom validator?

I have a validator that checks if username is already registered in database. It worked fine, except for the fact, that the request was send to the server with each character entered - which is way to often. So i tried to debounce the setting of the username variable value but all i'm getting is this:

Uncaught TypeError: Cannot read property 'value' of undefined 
at a.NHnr.q.methods.debounceUsername.H.a.debounce.leading

Vue script:

import uniqueUsername from '../validation/uniqueUsername'
import _ from 'lodash'

export default {
    name: "signUpPage",
    data() {
      return {
        credentials: {
          username: ''
        }
      }
    },
    methods: {
      debounceUsername:
        _.debounce(function (e) {
          this.credentials.username = e.target.value;
        }, 200, {leading: false, trailing: true})
    },
    validations: {
      credentials: {
        username: {
          uniqueUsername: uniqueUsername
        }
      }
   }
}

Html:

    <b-field :label="msg('usernameLabel')"
             :class="{ 'form-group--error': $v.credentials.username.$error }">
      <b-input size="is-large" type="text" class="form__input"
               icon="account" name="username" v-on:input="debounceUsername" autofocus="">
      </b-input>
    </b-field> 
//b-field and b-input are from buefy library

Custom validator (uniqueUsername.js):

import axios from 'axios'

export default value => {
  if (value.trim().length === 0) return true;
  let usernameUnique;
  return new Promise(async function (resolve) {
    await axios('/isUsernameUnique', {
      method: "post",
      data: value,
      headers: {'Content-type': 'text/plain'}
    }).then((response) => usernameUnique = response.data);
    if (usernameUnique) resolve('username is unique');
  });
};
like image 730
Jakubeeee Avatar asked Mar 08 '18 17:03

Jakubeeee


2 Answers

One solution is to check when the user focused out of input field (blur) and then to run the async validations.So:

<input @blur="$v.username.$touch" v-model.lazy="username" />

The script:

export default {
  data () {
   return {
    username: ''
   }
  },
  validations: {
    username: {
     required,
     isUnique(username) {
       if (username === '') return true
       return axios.get('/checkUsername')
                 .then(res => {
                   return res.data //res.data has to return true or false after checking if the username exists in DB
                 }) 
     }
    }
  }
}

Note: in order to work this code you have to import axios and required from vuelidate

Also keep in mind.The backend has to return false if the username is unique in order the above code to work correctly

like image 99
Roland Avatar answered Nov 15 '22 02:11

Roland


I found the answer. I had to change

this.credentials.username = e.target.value;

to:

this.credentials.username = e;

and it works now - frequency of sending requests is now max one every 200ms

like image 2
Jakubeeee Avatar answered Nov 15 '22 01:11

Jakubeeee