[Vuejs]-Form inputs don't get validated while typing (@input), only @blur works

0๐Ÿ‘

v-combobox emits change or input events only when one of its valid values from the dropdown are selected. The text entered in the combobox is actually search input, used to lookup a valid value; and that entry is bound to v-comboboxโ€˜s search-input prop.

The v-combobox API lists update:search-input as an event that is fired when the search input changes, so you could use that to bind the validation handler:

<!-- BEFORE: -->
<v-combobox @input="$v.surname.$touch()">

<!-- AFTER: -->
<v-combobox @update:search-input="$v.surname.$touch()">

0๐Ÿ‘

I used to have a component wrapper around v-combobox, v-autocomplete and v-select (yes, single multi-purpose wrapper). And I would recommend using the code below in a wrapper to avoid copy pasting the fix/workaround.

In general workaround required lookup into Vuetify sources. This led to manipulating errorBucket and valid in @update:search-input listener.

Additionally you might want to emit 'input'. It requires one small tweak to suppress propagation into v-combobox value, since it breaks autocomplete behavior otherwise. Hence if (this.search) { return; }

Full example: Codepen

Vue.component(
  'my-combobox', {
  template: `
      <v-combobox
         ref="combobox"
         outlined dense
         v-model="selection"
         v-bind="{ ...$attrs, items, rules: validationRules }"
         v-on="$listeners"
         @update:search-input="onSearch"
         @focus="touched = true"></v-combobox>
      `,
  props: {
    value: String,
    items: Array,
    required: Boolean,
    rules: Array,
  },
  data() {
    return {
      selection: null,
      search: null,
      touched: false,
    };
  },
  computed: {
    validationRules() {
      return [
        ...(this.rules || []),
        (v) => !this.required || (v?.length ?? 0) > 0 || 'Value is required',
      ];
    },
  },
  methods: {
    onSearch(v) {
      if (!this.touched) return;
      this.search = v;
      const $self = this.$refs.combobox;
      $self.errorBucket = this.validationRules.filter(f => f(v) !== true);
      $self.valid = $self.errorBucket.length === 0;
      this.$emit('input', v);
    },
  },
  watch: {
    selection: {
      handler(v) {
        this.$emit('input', v);
      },
    },
    value: {
      immediate: true,
      handler(v) {
        if (this.search) { return; }
        this.selection = v;
      },
    },
  },
});

Leave a comment