How to make checkbox selected with v-model value for vue-multiselect

Viewed 1232

Question: on created selected option checkbox is not getting selected, i want checkbox to be selected irrespective checked true/false

Note: value model i always want without checked state into it

below image shows my problem(please see yellow area)

enter image description here

here is what i have tried:

new Vue({
    components: {
    Multiselect: window.VueMultiselect.default
    },
    data: {
    value: [],
    options: [
        {   language: 'JavaScript', library: 'Vue.js', checked: false },
      { language: 'JavaScript', library: 'Vue-Multiselect', checked: false },
      { language: 'JavaScript', library: 'Vuelidate', checked: false }
    ]
    },
  methods: {
    customLabel (option) {
      return `${option.library} - ${option.language}`
    },
    onSelect (option) {
        console.log("Added");
      let index = this.options.findIndex(item => item.library==option.library);
      this.options[index].checked = true;
      console.log(option.library + "  Clicked!! " + option.checked);
    },
    
    onRemove (option) {
        console.log("Removed");
      let index = this.options.findIndex(item => item.library==option.library);
      this.options[index].checked = false;
      console.log(option.library + "  Removed!! " + option.checked);
    }
  },
  created(){
       this.value = [{  language: 'JavaScript', library: 'Vue.js',checked:true }];
  }
}).$mount('#app')
* {
  font-family: 'Lato', 'Avenir', sans-serif;
}

.checkbox-label {
  display: block;
}

.test {
  position: absolute;
  right: 1vw;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<link href="https://unpkg.com/vue-multiselect@2.0.2/dist/vue-multiselect.min.css" rel="stylesheet"/>
<script src="https://unpkg.com/vue-multiselect@2.0.3/dist/vue-multiselect.min.js"></script>
<div id="app">
  <multiselect 
    select-Label=""
    selected-Label=""
    deselect-Label=""
    v-model="value" 
    :options="options"
    :multiple="true"
    track-by="library"
    :custom-label="customLabel"
    :close-on-select="false"
    @select=onSelect($event)
    @remove=onRemove($event)
    >
    <span class="checkbox-label" slot="option" slot-scope="scope" @click.self="select(scope.option)">
    {{ scope.option.library }}
      <input class="test" type="checkbox" v-model="scope.option.checked" @focus.prevent/>
      
    </span>
  </multiselect>
  <pre>{{ value }}</pre>
</div>

please help me thanks in advance!!

3 Answers

You don't need to assign the value as it loses its reactivity there. You just have to select the right option and make it checked. As the below code I've changed the created block

new Vue({
  components: {
    Multiselect: window.VueMultiselect.default
  },
  data: {
    value: [],
    options: [{
        language: 'JavaScript',
        library: 'Vue.js',
        checked: false
      },
      {
        language: 'JavaScript',
        library: 'Vue-Multiselect',
        checked: false
      },
      {
        language: 'JavaScript',
        library: 'Vuelidate',
        checked: false
      }
    ]
  },
  methods: {
    customLabel(option) {
      return `${option.library} - ${option.language}`
    },
    onSelect(option) {
      console.log("Added");
      let index = this.options.findIndex(item => item.library == option.library);
      this.options[index].checked = true;
      console.log(option.library + "  Clicked!! " + option.checked);
    },

    onRemove(option) {
      console.log("Removed");
      let index = this.options.findIndex(item => item.library == option.library);
      this.options[index].checked = false;
      console.log(option.library + "  Removed!! " + option.checked);
    }
  },
  created() {
    // this.value = this.options[0];
    //this.value.checked = true;

    this.value.push(this.options[0]);
    this.value.push(this.options[1]);

    for (let i = 0; i < this.value.length; i++) {
      this.value[i].checked = true;
    }

  }
}).$mount('#app')
* {
  font-family: 'Lato', 'Avenir', sans-serif;
}

.checkbox-label {
  display: block;
}

.test {
  position: absolute;
  right: 1vw;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<link href="https://unpkg.com/vue-multiselect@2.0.2/dist/vue-multiselect.min.css" rel="stylesheet" />
<script src="https://unpkg.com/vue-multiselect@2.0.3/dist/vue-multiselect.min.js"></script>
<div id="app">
  <multiselect select-Label="" selected-Label="" deselect-Label="" v-model="value" :options="options" :multiple="true" track-by="library" :custom-label="customLabel" :close-on-select="false" @select=onSelect($event) @remove=onRemove($event)>
    <span class="checkbox-label" slot="option" slot-scope="scope" @click.self="select(scope.option)">
    {{ scope.option.library }}
      <input class="test" type="checkbox" v-model="scope.option.checked" @focus.prevent/>
      
    </span>
  </multiselect>
  <pre>{{ value }}</pre>
</div>

It's a bit hard to understand what you actually want but assuming:

  1. You want to render checkboxes
  2. You don't want checked field in the v-model (so it was added only to help render the checkboxes)

You don't need checked property at all as the value can be easily replaced by simple check against the v-model. That way you can remove a lot of unnecessary code.

See my example below:

new Vue({
  components: {
    Multiselect: window.VueMultiselect.default
  },
  data: {
    value: [],
    options: [{
        language: 'JavaScript',
        library: 'Vue.js'
      },
      {
        language: 'JavaScript',
        library: 'Vue-Multiselect'
      },
      {
        language: 'JavaScript',
        library: 'Vuelidate'
      }
    ]
  },
  methods: {
    customLabel(option) {
      return `${option.library} - ${option.language}`
    },
    isSelected(option) {
      /* unfortunatelly following line does not work as VueMultiselect for some (strange) reason 
        fills the v-model array with copies instead of original objects contained in options
      */
      // return this.value.includes(option)
      return this.value.some((op) => op.library === option.library)
    }
  },
  created() {
    this.value.push(this.options[0])
  }
}).$mount('#app')
* {
  font-family: 'Lato', 'Avenir', sans-serif;
}

.checkbox-label {
  display: block;
}

.test {
  position: absolute;
  right: 1vw;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<link href="https://unpkg.com/vue-multiselect@2.0.2/dist/vue-multiselect.min.css" rel="stylesheet" />
<script src="https://unpkg.com/vue-multiselect@2.0.3/dist/vue-multiselect.min.js"></script>
<div id="app">
  <multiselect select-Label="" selected-Label="" deselect-Label="" v-model="value" :options="options" :multiple="true" track-by="library" :custom-label="customLabel" :close-on-select="false">
    <span class="checkbox-label" slot="option" slot-scope="scope">
    {{ scope.option.library }}
      <input class="test" type="checkbox" :checked="isSelected(scope.option)" @focus.prevent :key="scope.option.library" />
    </span>
  </multiselect>
  <pre>{{ value }}</pre>
</div>

The package is not working as checkboxes, but more as an array of options, that you can select or not. So if you want to have the options preselected, you have to add them on your v-model array ("value" in this case).

Also the options.checked data is cargo cult here. They are not used for anything.

Example based on your code. your data() should be

options: [
        {   language: 'JavaScript', library: 'Vue.js'},
      { language: 'JavaScript', library: 'Vue-Multiselect'},
      { language: 'JavaScript', library: 'Vuelidate' }
    ],
value: [
        {   language: 'JavaScript', library: 'Vue.js'},
      { language: 'JavaScript', library: 'Vue-Multiselect'},
      { language: 'JavaScript', library: 'Vuelidate' }
    ]

If you start the app using these two in your data, all the options will be preselected.

Related