D
D
danilr2019-03-17 11:09:25
Vue.js
danilr, 2019-03-17 11:09:25

How to correctly check the input value for validity and correctly build its architecture?

There is an input (in this case it is in the component), it has props - "invalid" if it is true, then the input is highlighted with a red frame. The question is what is correct and should be substituted into this prop? I do as below, but it seems to me very wrong, because for the sake of one input, a lot of code is obtained, and I can have up to 30 of these inputs.
This is how I do it, how wrong and how can I optimize?:
This is the component itself with an input:

<InputText
              @input="handleNameGroup($event)"
              :value="this.formGroupData.comment"
              :invalid="invalidFormName && invalidName"
            >
            </InputText>

Here I specifically create a variable for each input only for validation
export default {
  data(){
    return{
      formGroupData:{
        comment: '',
        group_id : '',
        id: ''
      },
      invalidSelect: false  
    }
  },

here is the second variable calculated by the computer
computed:{
    invalidFormName(){
      return !this.formGroupData.comment.length
    },

Here, when you click on the save button, again I check the validation with these variables
handleSaveGroup(){
      if(!this.formGroupData.comment || !this.formGroupData.group_id){
        this.invalidName = !this.formGroupData.comment ? true : false
        return false 
      }

There is a lot of superfluous and wrong in my opinion, but I don’t know how to do it differently, so I turn to you for help

Answer the question

In order to leave comments, you need to log in

2 answer(s)
K
karambafe, 2019-03-17
@danilr

Standard problem with custom inputs and form validation.
One solution is to create a single error array in the form with pointers pointing to a specific input. This is especially good when the backend at the form validation stage also returns errors with specific pointers.
An example of a custom input with error text displayed below it. If there is at least one error, then an "erroneous" class with its own styles is hung.

<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>

And in the form, we already distribute all the errors to the necessary inputs:
<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>

This may be verbose code, but it is well read, understandable and extremely easy to cover with unit tests.

F
Fedor Grebennikov, 2016-11-26
@zaxx784

var item = document.getElementsByTagName('li');           //Выбираем все li-шки в документе
for (var i = 0; i < item.length; i++){                   //Запускаем цикл для перебора всех li
  item[i].style.position = 'relative';                   //Каждому li устанавливаем css-свойство "position: relative"
  var span = document.createElement('span');             // Создаем span
  span.style.cssText = 'position:absolute;left:0;top:0'; //Присваиваем созданному спану стили
  item[i].appendChild(span);                              //Помещаем span в li
}

In general, we set relative positioning to all elements of the list (li) and add a span with our own styles to each

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question