Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Vue, how to cancel a checkbox based on a condition?

I want to always have at least one checkbox checked but I mix the concepts of v-model and :checked.

The doc says:

v-model will ignore the initial value, checked or selected attributes found on any form elements. It will always treat the Vue instance data as the source of truth.

I can prevent my model to be modified but I can't prevent the checkbox to be checked...

Some code:

The template

<div class="wrapper" v-for="(s, id) in userOutputSeries" :key="id">
  <input type="checkbox" :id="id" :value="id" @change="preventIfLessThanOneChecked" :checked="s.active">
  <label :for="id">{{ s.display }}</label>
</div>

The model userOutputSeries

data () {
  return {
    userOutputSeries: {
      foo: {
        display: 'Awesome Foo',
        active: true
      },
      bar: {
        display: 'My Bar',
        active: false
      }
    }
  }
}

The preventIfLessThanOneChecked handler

preventIfLessThanOneChecked (event) {
  // I don't update the model so it stay at the same state
  // But only need to count the active series and do what we want.
  console.log(event.target.value, event.target.checked)
}

Any ideas to stop the native checkbox propagation?

like image 216
Existe Deja Avatar asked Oct 10 '17 16:10

Existe Deja


2 Answers

You should use v-model instead of :checked so that changes to the userOutputSeries data property will be reflected in the checkbox input.

Then, pass the s reference from the v-for to the method and set that object's active property to true if there are no active checkboxes:

new Vue({
  el: '#app',
  data() {
    return {
      userOutputSeries: {
        foo: {
          display: 'Awesome Foo',
          active: true
        },
        bar: {
          display: 'My Bar',
          active: false
        }
      }
    }
  },
  methods: {
    preventIfLessThanOneChecked(item) {
      if (item.active) {
        return;
      }
    
      let items = Object.values(this.userOutputSeries);
      if (!items.find(i => i.active)) {
        item.active = true;
      }
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.4/vue.min.js"></script>
<div id="app">
  <div class="wrapper" v-for="(s, id) in userOutputSeries" :key="id">
    <input type="checkbox" :id="id" :value="id" @change="preventIfLessThanOneChecked(s)" v-model="s.active">
    <label :for="id">{{ s.display }}</label>
  </div>
</div>
like image 125
thanksd Avatar answered Oct 28 '22 20:10

thanksd


Try using disabled on your single checked checkbox:

<div class="wrapper" v-for="(s, id) in userOutputSeries" :key="id">
  <input type="checkbox" :id="id" :value="id"
      :disabled="(s.active && numberOfChecked == 1) ? disabled : null"
      @change="preventIfLessThanOneChecked" :checked="s.active">
  <label :for="id">{{ s.display }}</label>
</div>
like image 44
Sui Dream Avatar answered Oct 28 '22 20:10

Sui Dream