Задать вопрос
amux
@amux
alp.ac

Как делать валидацию инпутов в Vue.js использующих v-model?

Есть 5 переменных:

all_values: 1000
value_1: 100
value_2: 100
value_3: 150
value_4: 150

Сумма всех переменных value_[1-4] не должна быть больше all_values,
Как добавить валидацию к v-model, чтобы, если вводимое значение не валидно, в инпут шло предыдущее валидное значение?

- Инпуты могут быть в разных компонентах, связаны через Vuex
- Пробовал через v-directive, но так и не придумал как пропустить значение переменной в функцию.
  • Вопрос задан
  • 331 просмотр
Подписаться 1 Простой Комментировать
Пригласить эксперта
Ответы на вопрос 2
kulakoff
@kulakoff Куратор тега Vue.js
Vue.js developing
Не использовать v-model, а использовать отдельно :value и @input. В @input делать вадидацию.
Ещё менее предпочтительней вариант имхо, следить через watch за переменной привязанной к v-model и делать валидацию.
Ответ написан
Комментировать
0xD34F
@0xD34F Куратор тега Vue.js
Значения сложим в объект (это если надо оставить человекопонятные имена) или массив:

data: () => ({
  maxSum: 1000,
  values: {
    v1: 69,
    v2: 187,
    v3: 666,
    v4: -100,
  },
},

Сделаем пару вычисляемых свойств - копию значений и их сумму:

computed: {
  valuesCopy() {
    return { ...this.values };
  },
  sum() {
    return Object.values(this.values).reduce((acc, n) => acc + n, 0);
  },
},

Установим наблюдение за копией, где, в случае некорректности суммы, предыдущая копия будет устанавливаться в качестве актуальных значений:

watch: {
  valuesCopy(newVal, oldVal) {
    if (!Number.isFinite(this.sum) || this.sum > this.maxSum) {
      this.values = oldVal;
    }
  },
},

https://jsbin.com/suxefokune/edit?html,js,output

Инпуты могут быть в разных компонентах, связаны через Vuex

Данные уносим в хранилище.

Создаём мутацию для обновления данных. Внутри вычисляем новую сумму, если она не превышает максимально допустимую, то сохраняем значение. В противном случае заменяем значения их копией (да, значения в хранилище всё ещё корректны, но вот в компоненте в input'е мусор, надо обновить):

mutations: {
  setValue(state, [ key, val ]) {
    const sum = Object
      .entries(state.values)
      .reduce((acc, n) => acc + (n[0] === key ? val : n[1]), 0);

    if (sum <= state.maxSum) {
      state.values[key] = val;
    } else {
      state.values = Object.assign({}, state.values);
    }
  },
},

Собственно компонент для редактирования значений - принимает ключ, по которому вытягивает значение из хранилища, и дёргает мутацию для сохранения нового значения:

Vue.component('v-input', {
  props: [ 'storeKey' ],
  template: `
    <input
      :value="$store.state.values[storeKey]"
      @input="$store.commit('setValue', [ storeKey, +$event.target.value ])"
    >`,
});

Создаём столько экземпляров, сколько потребуется:

<div v-for="(v, k) in $store.state.values">
  {{ k }}: <v-input :store-key="k"></v-input>
</div>
<div>
  ещё раз v3: <v-input store-key="v3"></v-input>
</div>
<div>
  и v2 тоже: <v-input store-key="v2"></v-input>
</div>

https://jsbin.com/zinenazitu/edit?html,js,output
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы