Я пытаюсь реализовать VeeValidate, чтобы проверить, установлен ли хотя бы один флажок

Я нашел пример jsfiddle, который я раздвоил, а затем отредактировал. Я не понимаю, что происходит или как это исправить. В моем примере я использую флажки со значениями, но когда я нажимаю флажок, значение изменяется на true или false в зависимости от того, установлен ли флажок.

const Checkboxes = {
 template: '#checkboxTmpl',
  data() {
   return {
     text: '',
     options: [
       {
         name: 'Web',
         slug: 'web'
        },
        {
         name: 'iOS',
         slug: 'ios'
        },
        {
         name: 'Android',
         slug: 'android'
        }
      ]
    };
  },
  created() {
   this.$validator.extend('oneChecked', {
        getMessage: field => 'At least one ' + field + ' needs to be checked.',
        validate: (value, [testProp]) => {
          const options = this.options;
          // console.log('questions', value, testProp, options.some((option) => option[testProp]));
          return value || options.some((option) => option[testProp]);
        }
      });
  },
  methods: {
   validateBeforeSubmit(e) {
      this.$validator.validateAll(); // why is oneChecked not validated here? --> manually trigger validate below
      this.options.forEach((option) => {
       this.$validator.validate('platforms', option.slug, ['checked'])
      });
      
      console.log('validator', this.errors);
      if (!this.errors.any()) {
          alert('succesfully submitted!');
      } 
    }
  }
};

Vue.use(VeeValidate);

const app = new Vue({
 el: '#app',
  render: (h) => h(Checkboxes)
})
<script src="https://cdn.jsdelivr.net/vee-validate/2.0.0-beta.18/vee-validate.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.8/vue.js"></script>
<div id="app">

</div>

<script id="checkboxTmpl" type="text/template">
 <form @submit.prevent="validateBeforeSubmit">
  
   <label v-for="(option, index) in options">
     <input type="checkbox" 
       v-model="option.slug"
        name="platform"
        v-validate.initial="option.slug"
        data-vv-rules="oneChecked:checked" 
        data-vv-as="platform"/> {{option.name}}
    </label>

    <p v-show="errors.has('platform')">{{ errors.first('platform') }}</p>
    
    <pre>{{options}}</pre>
    
    <button type="submit">Submit</button>
  </form>
</script>

Я не понимаю, почему все флажки установлены, и снятие отметки с одного из них возвращает ошибку проверки, хотя два все еще проверены. Мне нравится, что ошибки отображаются перед отправкой формы, но снятие отметки со всех и последующая отправка не вызывает ошибку проверки.

Я использую VeeValidate, потому что это то, что используется в примере, но любое другое решение будет хорошо. Я не хочу использовать jQuery в своем приложении vue.js.

Мне бы очень хотелось понять, что происходит.

1 ответ

Решение

Там было две основные проблемы:

  1. С помощью v-model на неправильном ключе. Фактически, каждый раз, когда флажок был отмечен или снят, он будет генерировать событие ввода, которое изменит исходный фрагмент параметра (в вашем data). Вместо этого вам нужно добавить checked поле в вашем варианте. Затем в вашем шаблоне добавьте :checked приписать и изменить ваш v-model быть :option.checked,
  2. Как сказано в документах VeeValidate, вы можете просто использовать required правило, чтобы убедиться, что флажок должен быть установлен для отправки вашей формы. Вот ссылка на документы. Поэтому вам не нужны ваши created блок.

Кроме того, validateAll Функция возвращает обещание, содержащее результат проверки. Так что не нужно использовать this.errors.any() тоже.

Кроме того, я обновил библиотеку VeeValidate до последней версии, поскольку вы использовали бета-версию.

Вот рабочий код:

const Checkboxes = {
  template: '#checkboxTmpl',
  data() {
    return {
      text: '',
      options: [{
          name: 'Web',
          slug: 'web',
          checked: false
        },
        {
          name: 'iOS',
          slug: 'ios',
          checked: true
        },
        {
          name: 'Android',
          slug: 'android',
          checked: true
        }
      ]
    };
  },
  methods: {
    validateBeforeSubmit(e) {
      this.$validator.validateAll().then(value => {
        if (value) {
          alert('successfully submitted')
        }
      })
    }
  }
};

Vue.use(VeeValidate);

const app = new Vue({
  el: '#app',
  render: (h) => h(Checkboxes)
})
<div id="app"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.8/vue.js"></script>
<script src="https://unpkg.com/vee-validate@latest"></script>

<script id="checkboxTmpl" type="text/template">
  <form @submit.prevent="validateBeforeSubmit">

    <label v-for="(option, index) in options">
     <input type="checkbox"
       :checked="option.checked"
        v-model="option.checked"
        name="platform"
        v-validate="'required'"/> {{option.name}}
    </label>

    <p v-show="errors.has('platform')">{{ errors.first('platform') }}</p>

    <pre>{{options}}</pre>

    <button type="submit">Submit</button>
  </form>
</script>

Надеюсь, это поможет!

Другие вопросы по тегам