0
votes

I am trying to create multi-select questions in vue using v-for.

The Select menu and the options are populated through JSON.

I am not able to fetch the results of the selection as expected.

While I select the options, I am unable to persist the values data.

for eg: while I select any option from the 2nd menu, the selection in the 1st menu is cleared. Vice-versa for 1st menu.

new Vue({
  el: "#app",
  data: {
    selectedValue: [],
    checklists: [
      {
   "id":1,
   "heading":"Environment",
   "deleted_at":null,
   "created_at":null,
   "updated_at":"2020-08-08T13:24:22.000000Z",
   "checklist_value":[
      {
         "id":1,
         "checklists_id":1,
         "values":"Indoor",
         "notes":null,
         "deleted_at":null,
         "created_at":"2020-08-08T13:03:50.000000Z",
         "updated_at":"2020-08-08T13:03:50.000000Z"
      },
      {
         "id":2,
         "checklists_id":1,
         "values":"Outdoor",
         "notes":null,
         "deleted_at":null,
         "created_at":"2020-08-08T13:13:27.000000Z",
         "updated_at":"2020-08-08T13:13:27.000000Z"
      }
   ]
},
{
   "id":2,
   "heading":"Location of Camera's",
   "deleted_at":null,
   "created_at":"2020-08-08T11:41:31.000000Z",
   "updated_at":"2020-08-08T13:27:59.000000Z",
   "checklist_value":[
      {
         "id":3,
         "checklists_id":2,
         "values":"Parking",
         "notes":null,
         "deleted_at":null,
         "created_at":"2020-08-08T13:28:45.000000Z",
         "updated_at":"2020-08-08T13:28:45.000000Z"
      },
      {
         "id":4,
         "checklists_id":2,
         "values":"Balcony",
         "notes":null,
         "deleted_at":null,
         "created_at":"2020-08-08T13:28:53.000000Z",
         "updated_at":"2020-08-08T13:28:53.000000Z"
      }
   ]
}

    ]
  },
  

  methods: {
    getSelectedID(event) {
      console.log(this.selectedValue);
    }
  }
  
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
  <div class="input-field col s12" v-for="(checklist, index) in checklists">
    <select v-model="selectedValue" @change="getSelectedID($event)" multiple="multiple">
      <option disabled>Choose options</option>
      <option v-for="(value,index) in checklist.checklist_value" :value="value.id">{{value.values}}</option>
    </select>
    <label>{{checklist.heading}}</label>
  </div>
</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
<script>
  $(document).ready(function() {
    $('select').formSelect();
  });

</script>

Expecting that v-model should create a new object for the select menu and map the options as an array so that I could pass it to the database and save them.

I would appreciate if you could brief me where I was wrong.

fiddle: https://jsfiddle.net/dvwkz15c/

1

1 Answers

2
votes

You're assigning the same variable each time you change the value of your select elements since they are both using the same v-model. You have the selectedValue set to be an array, but you need it to be a nested array so your results know not to overwrite themselves.

Simply add an index to each of your v-models so that it knows which part of the selectedValue array to overwrite when a value is changed or added.

<div class="input-field col s12" v-for="(checklist, index) in checklists">
    <select v-model="selectedValue[index]" @change="getSelectedID($event)" multiple="multiple">
    ...
</div>

New Edit:

Sorry about that, my previous answer worked in the fiddle maybe due to some sort of versioning difference. Anyways, the new error you're getting can be fixed by defining the indices in the Vue data function like so:

<select v-model="selectedValues[index]['values']"  multiple="multiple">

then change array definition to an object definition with child arrays.

selectedValues: [
    { "values": []},
    { "values": []},
],

You could add this manually each time you add a checklist (which would be a pain) or you could set up a Vue mounted function which gets the length of your checklists array and automatically creates that many object indices within the selectedValues array.

Mounted Example

selectedValues: [],

...

mounted: function() { 
    for(let i=0; i < this.checklists.length; i ++) {
        this.selectedValues.push({
            "values": []
        });
    }
}

This will create the indices in the array whenever the component is mounted in your application. Depending on how your data is loaded, you may need to surround the for loop in Vue.nextTick(function() { ... }); If you do this you will need to change the scope of "this" however.

If you're also loading your data via an Ajax response, you could place the loop instead in a method that you can call on mount and after your Ajax call. But since it's using push(..) you'll want to reset the array before doing so this.selectedValues = []; ... (for loop)...