@danilr

Как правильно проверять на валидность значение input и правильно выстроить ее архитектуру?

Есть input (в данном случае он в компоненте), у него есть props - "invalid" если он true, то инпут подсвечивается красной рамкой. Вопрос в том, что правильно и нужно подставлять в этот пропс? Я делаю так, как ниже, но мне кажется это очень неправильно ибо ради одного input получается очень много кода, а этих инпутов у меня может быть до 30 штук.
Вот так делаю, насколько неправильно и как можно оптимизировать?:
Это сам компонент с инпут:
<InputText
              @input="handleNameGroup($event)"
              :value="this.formGroupData.comment"
              :invalid="invalidFormName && invalidName"
            >
            </InputText>

Здесь специально создаю под каждый инпут переменную только для валидации
export default {
  data(){
    return{
      formGroupData:{
        comment: '',
        group_id : '',
        id: ''
      },
      invalidSelect: false  
    }
  },

тут вторая переменная, вычисляемая компьютед
computed:{
    invalidFormName(){
      return !this.formGroupData.comment.length
    },

Здесь при нажатии на кнопку созранить, опять же проверяю валидацию этими переменными
handleSaveGroup(){
      if(!this.formGroupData.comment || !this.formGroupData.group_id){
        this.invalidName = !this.formGroupData.comment ? true : false
        return false 
      }

Очень много лишнего и неправильного на мой взгляд, но как по другому сделать я не знаю, поэтому обращаюсь к вам за помощью
  • Вопрос задан
  • 524 просмотра
Решения вопроса 1
@karambafe
Стандартная проблема с кастомными инпутами и валидацией в форме.

Одно из решений - в форме создать один массив ошибок с поинтерами, указывающими на определенный input. Особенно это хорошо, когда бекенд на этапе проверки формы возвращает ошибки тоже с конкретными поинтерами.

Пример кастомного инпута c выводом текста ошибки под ним. Если есть хоть одна ошибка, то навешивается "ошибочный" класс со своими стилями.
<template>
  <div class="input">
    <input
      type="text"
      class="input__field"
      :class="{ 'input__field_error': errors.length > 0 }"
      :placeholder="placeholder"
      :value="value"
      :disabled="disabled"
      @input="handleInput"
    >

    <div class="input__errors">
      <p
        v-for="(error, index) in errors"
        :key="index"
        class="input__error"
      >
        {{ error }}
      </p>
    </div>
  </div>
</template>

<script>
export default {
  name: 'custom-input',
  props: {
    disabled: {
      type: Boolean,
      default: false,
    },
    errors: {
      type: Array,
      default: () => ([]),
    },
    value: {
      type: String,
      default: '',
    },
    placeholder: {
      type: String,
      default: '',
    },
  },
  methods: {
    handleInput({ target: { value } }) {
      this.$emit('onInput', value);
    },
  },
};
</script>


А в форме уже мы распределяем все ошибки по нужным инпутам:
<template>
<form @onSubmit.prevent="handleSubmit">
  <custom-input
     :value="phone"
     :disabled="loading"
     :errors="phoneErrors" // передаем только относящиеся к конкретному инпуту ошибки
     @onInput="handleInput"
  />

  <button type="submit">Отправить</button>
</form>
</template>

<script>
export default {
  data: () => ({
     phone: '',
     errors: [],
     loading: false,
  }),
  computed: {
     phoneErrors() {
       // этот код лучше вынести в хелпер, чтобы потом переиспользовать с другими поинтерами
        if (this.errors.length === 0) return [];
        
        return this.errors
         .filter(error => error.pointer === 'phone') // проверка на нужный поинтер
         .map(item => item.detail); // делаем массив только из текста ошибок
     },
  },
  methods: {
    handleInput(newPhone) {
     // при вводе нового значения обнуляем все ошибки. 
     // Можно сделать обнуление ошибок по конкретному поинтеру
      this.errors = []; 
      this.phone = newPhone;
    },
    handleSubmit() {
        this.errors = [];

       // Если инпут пустой, то сами генерируем ошибку
       // и не делаем отправку данных на сервер
       if (this.phone.length === 0) {
        this.errors = [...this.errors, {
          detail: 'Телефон не может быть пустым',
          pointer: 'phone',
        }];
        return;
      }

      // Если же все ок, то отправляем данные на сервер
      this.loading = true;
      this.sendPhone();
    },
  },
};
</script>


Возможно это и многословный код, но он хорошо читается, понятен и крайне легко покрывается unit тестами
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

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

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