Click on checkbox option deselect other options

Asked

Viewed 265 times

0

I have a component in Vue that I pass a prop with the options and it generates a several checkbox for min, what is necessary is that when checking the option "none of the alternatives" it unchecks the other alternatives if they are marked, and vice versa. My component now:

 <template>
  <div class="form-group">
    <label class="mb-2" v-if="label">
      {{ label }}
    </label>
    <div class="form-check p-0" v-for="(option, index) in options" :key="index">
      <div class="custom-control custom-checkbox">
        <input
          type="checkbox"
          class="custom-control-input"
          :id="option"
          :value="option"
          v-model="checkeds"
        />
        <label class="custom-control-label" :for="option">{{ option }}</label>
      </div>
    </div>
    <div class="feedback-checkbox" v-show="error">{{ error }}</div>
  </div>
</template>
<script>
export default {
  name: 'CheckboxInput',
  $_veeValidate: {
    value () {
      return this.value
    },
    name () {
      return this.name
    }
  },
  props: ['label', 'name', 'value', 'validations', 'options', 'error'],
  watch: {
    checkeds (newValue) {
      this.$emit('input', newValue)
    }
  },
  data () {
    return {
      checkeds: []
    }
  }
}
</script>
  • Igor, you want a checkbox behave like radio button? Wouldn’t it be easier for you to use radio?

  • I also thought about it, but by the requirement of the project the user can mark 2 options, so the radio does not serve. is like: problem1, problem2, uninformed problem, he may have had the 2 problems

  • I got it wrong Igor, I’m sorry. I’ll think of something to help you.

1 answer

1


One way for you to solve your problem is to treat the "No alternative" option as a special option. That is, it will not be included in data.options or data.checkeds because it has a special behavior.

The basic idea is to have:

  1. A array of _strings with the options (which is already yours prop that you call options)
  2. A array of boolean values of the same size as the checkbox of its component.
  3. One computed Property which will return the checkbox status "No alternative". That is, it will be true only if all the checkboxes are unchecked.
  4. A method to "zero" the checkboxes, that is, a method that you will assign false for all values of the array that stores the states of the checkboxes (item 2 of this list).

Basically what I do is guard the states (checked) in a array separate and have a method that assigns false for these states. A computed Property serves only as a feedback visual for the user, that is, if no alternative is checked, the option "No option" will be checked, otherwise it will be unchecked.

That said, the following code does exactly what the above list suggests. The only difference is that I run the method that "Zera" the checkboxes when starting the component, so data.checked is started with the same number of elements from data.options.

Code

new Vue({
    el: '#app',
    data: () => ({
        // Este array será dinâmico no componente pois será um prop
        options: ['Opção A', 'Opção B', 'Opção C'],
        // Deve ser iniciado com o mesmo tamanho de `options`
        checked: [],
    }),
    methods: {
        // Cria um array com N elementos de valor "false"
        resetChecked() {
            this.checked = Array(this.options.length).fill(false);
        }
    },
    computed: {
        // É true apenas se todos elementos de `checked` forem `false`
        nenhumaOpcao() {
            return this.checked.every(c => !c)
        }
    },
    // Inicia a variável `checked` ao montar o componente
    mounted() {
        this.resetChecked();
    }
})
.label { display: block; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
    <h3>Opções</h3>
    
    <!-- Opções dinâmicas do componente -->
    <label v-for="(option, i) in options" class="label">
      <input type="checkbox" :checked="checked[i]" v-model="checked[i]">
      {{ option }}
    </label>
    
    <!-- Opção fixa "Nenhuma opção" -->
    <label>
        <input type="checkbox" :checked="nenhumaOpcao" @click="resetChecked">
        Nenhuma opção
    </label>
</div>


Extra

resetChecked() {
    // Cria um array com N elementos de valor "false"
    this.checked = Array(this.options.length).fill(false);
}

In the above code I create a method to "zero" the _array _ checked using the constructor of Array and the method Array.fill.

The array builder, when you take an integer as argument, create an empty array of size N. Example:

let a = Array(3);
a[0];      // undefined
a[2];      // undefined
a[100];    // undefined
a.length;  // 3

While Array.fill fills an array with the received value. I use this method along with the above method to create an array with N values false to use in the component.

Array(5).fill(false); // [false, false, false, false, false]
Array(3).fill(0);     // [0, 0, 0]

If compatibility is a problem you can use any other method to create an array. Example:

function createArray(size, initial_value) {
    let new_array = [],
        i=0;

    for ( ; i < size ; i++) new_array.append(initial_value);

    return new_array;
}

nenhumaOpcao() {
    // É true apenas se todos elementos de `checked` forem false
    return this.checked.every(c => !c)
}

In the above code I use the method Array.every to test whether all elements of checked sane false. It is unlikely that you have problems from compatibility with this method, but for study purposes you could use something like:

function every(array, funcao) {
    for (let i=0, l=array.length ; i<l ; i++) {
        if (!funcao(array[i])) return false;
    }
    return true;
}
  • Perfect, I hadn’t thought of that fixed option, thank you!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.