tomexsans
tomexsans

Reputation: 4527

Bootstrap-vue Checkbox, Check additional options when selected

What i want to do is also check the default option when a user checks one of the checkbox item.

i have created a snippet of the error i am encountering, usually i thought its because of my nested components.

but i encountered the error You may have an infinite update loop in watcher with expression "localChecked"

even on this simple code snippet.

vue js script

new Vue({
  el: "#app",
  data: {
    application: [
            {
        app_name : 'Netflix',
        app_default : 'videoshare_default',
        options : [
          { text : 'Video Stream', value : 'video_streaming'},
          { text : 'Download Video' , value : 'video_download'},
          { text : 'Share Video' , value : 'videoshare_default'}
        ]
      },
            {
        app_name : 'Messenger',
        app_default : 'message',
        options : [
            { text : 'Messaging', value : 'message'},
          { text : 'Voice Calls' , value : 'voice_calls'},
          { text : 'Video Calls' , value : 'video_calls'},
          { text : 'Media Sharing' , value : 'file_transfer'}
        ]
      }      
    ],
    selected : []
  },
  methods: {
    selectDefault: function(data,$event){
        this.selected[data.app_name].push(data.videoshare_default)
    }
  }
})

HTML

<div id="app">
  <b-col v-for="(data , index) in application" v-bind:key="index" class="p-2" cols="5">
    <b-form-group :label="data.app_name" label-class="font-weight-bold">
      <b-form-checkbox-group                            
         @input="selectDefault(data,$event)"
         v-model="selected[data.app_name]"
         :options="data.options"
         name="application[]"
         stacked
      ></b-form-checkbox-group>
    </b-form-group>
  </b-col>
</div>

a FIDDLE:

https://jsfiddle.net/tomexsans/194m0jdq/1/

or is there any other way to do this than what i am doing.

Upvotes: 0

Views: 4935

Answers (1)

Hiws
Hiws

Reputation: 10324

Your selected property is an array, but you want to use key value pairs, which is why you need to make it an object instead, which will store an array of each application type.

To make sure that Vue stays reactive, you need to use the Vue.set or this.$set method to add a property to an object, if that property DOESN'T already exist in that object.

The $event on b-form-checkbox-group returns the entire array of selected values, which we don't want. That's why i use the .native modifier on the event, so i can access the clicked checkbox and it's value.

new Vue({
  el: "#app",
  data: {
    application: [{
        app_name: 'Netflix',
        app_default: 'videoshare_default',
        options: [{
            text: 'Video Stream',
            value: 'video_streaming'
          },
          {
            text: 'Download Video',
            value: 'video_download'
          },
          {
            text: 'Share Video',
            value: 'videoshare_default'
          }
        ]
      },
      {
        app_name: 'Messenger',
        app_default: 'message',
        options: [{
            text: 'Messaging',
            value: 'message'
          },
          {
            text: 'Voice Calls',
            value: 'voice_calls'
          },
          {
            text: 'Video Calls',
            value: 'video_calls'
          },
          {
            text: 'Media Sharing',
            value: 'file_transfer'
          }
        ]
      }
    ],
    selected: {}
  },
  methods: {
    selectDefault(data, event) {
      /*  Return if the checkbox was unchecked */
      if (!event.target.checked) return;
      /* Return if the selected value was the default */
      if (data.app_default === event.target.value) return;

      /* Init the array if it doesn't exist yet.*/
      if (!this.selected[data.app_name]) {
        this.$set(this.selected, data.app_name, []);
      }

      const nestedSelected = this.selected[data.app_name];
      /* Push in the default value if it doesn't exist alreayd */
      if (!nestedSelected.find(value => value === data.app_default)) {
        this.selected[data.app_name].push(data.app_default)
      }
    }
  }
})
<link href="https://unpkg.com/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://unpkg.com/[email protected]/dist/bootstrap-vue.css" rel="stylesheet"/>

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.js"></script>
<script src="https://unpkg.com/[email protected]/dist/bootstrap-vue.js"></script>

<div id="app">
  <b-col v-for="(data , index) in application" v-bind:key="index" class="p-2" cols="5">
    <b-form-group :label="data.app_name" label-class="font-weight-bold">
      <b-form-checkbox-group
         v-model="selected[data.app_name]"
         @input.native="selectDefault(data, $event)"
         :options="data.options"
         name="application[]"
         stacked
       ></b-form-checkbox-group>
    </b-form-group>
  </b-col>
  
  {{ selected }}
</div>

Upvotes: 1

Related Questions