我正在尝试实施 VeeValidate 以检查是否至少选中了一个复选框

I'm trying to implement VeeValidate to check if at least one checkbox is checked

我找到了一个 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>

我不明白为什么所有复选框都被选中并取消选中其中一个 returns 一个验证错误,即使两个仍然被选中。我喜欢在提交表单之前显示错误,但取消选中所有内容然后提交不会触发验证错误。

我正在使用 VeeValidate,因为这是该示例使用的,但任何其他解决方案都可以。我不想在我的 vue.js 应用程序中使用 jQuery。

我很想了解是怎么回事。

存在两个主要问题:

  1. 在错误的键上使用 v-model。事实上,每次选中或取消选中该复选框时,它都会发出一个输入事件,该事件将修改选项的原始 slug(在您的 data 中)。相反,您需要在选项中添加一个 checked 字段。然后在您的模板中添加 :checked 属性并将您的 v-model 修改为 :option.checked.
  2. 正如 VeeValidate 的文档所说,您可以只使用 required 规则来确保必须选中一个复选框才能提交您的表单。这是文档的 link 。因此,您不需要 created 块。

此外,validateAll 函数 returns 包含验证结果的承诺。所以也不需要使用 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>

希望对您有所帮助!