Search code examples
javascriptvue.jsvuejs2v-for

Vue dynamic v-model within v-for


I have the following fieldsets containing checkboxes:

<fieldset>
    <label v-for="(count, value) in availableFilters.level"><input type="checkbox" data-filterName="level" :value="value" v-model="level" @change="(e) => handleCheckbox(e, 'level')"> {{value}} ({{count}})</label>
</fieldset>
<fieldset>
    <label v-for="(count, value) in availableFilters.subject"><input type="checkbox" data-filterName="subject" :value="value" v-model="subject" @change="(e) => handleCheckbox(e, 'subject')"> {{value}} ({{count}})</label>
</fieldset>
<fieldset>
    <label v-for="(count, value) in availableFilters.delivery"><input type="checkbox" data-filterName="delivery" :value="value" v-model="name" @change="(e) => handleCheckbox(e, 'delivery')"> {{value}} ({{count}})</label>
</fieldset>

Notice there's a bit of repetition here, but it works. Here's my Vue instance:

var vm = new Vue({
    el: '#app',
    data: {
        level: [],
        subject: [],
        delivery: [],
        availableFilters: {
            level: {
                "UG": 12,
                "PG": 12,
            }
        }
    },
    ...

I want something more like this so I don't have to repeat the same block over again:

<fieldset v-for="(filters, name) in availableFilters">
    <label v-for="(count, value) in filters">
        <input type="checkbox" :data-filterName="name" :value="value" v-model="name" @change="(e) => handleCheckbox(e, name, value)"> {{value}} ({{count}})
    </label>
</fieldset>

However, this doesn't work and it seems that the v-model is not bound to the data property. How do I correctly pass that now? The data property name will be whatever name is.


Solution

  • To with situation you should put that properties (level, subject, delivery) inside an object called selected as follows :

     selected: {
        level: [],
        subject: [],
        delivery: []
      } 
    

    and you should loop using v-for like :

           <fieldset v-for="(filters, key,index) in availableFilters">
    

    where the filters represents the value, key represents the key like level and ìndex represents the index such 0, using the key item we could access selected like selected[key] so we could bind the checkbox to that property easily.

    Full example

    new Vue({
      el: '#app',
    
      data() {
        return {
          selected: {
            level: [],
            subject: [],
            delivery: []
          },
          availableFilters: {
            level: {
              "UG": 12,
              "PG": 12,
            },
            subject: {
    
            }
          }
        }
    
      }
     
    });
    <link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap/dist/css/bootstrap.min.css" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
    
    
    <div id="app" class="container">
      <fieldset v-for="(filters, key,index) in availableFilters">
        <label v-for="(count, value) in filters">
            <input type="checkbox" :data-filterName="this[filters]" :value="value"  v-model="selected[key]" @change="onchange"> {{value}} ({{count}})
        </label>
      </fieldset>
      <pre>{{selected}}</pre>
    </div>