4

I have a list of filters using checkboxes. I'm trying to make each checkbox it's own components. So I loop through my list of filters adding a checkbox component for each filter. The Vue.js documentation says that if I have multiple checkboxes that use the same model that array will get updated with the value of the checkboxes. I see that working if the group of checkboxes is part of the parent component. But if I make the checkbox a component and add each checkbox component in a loop then the model doesn't update as expected.

How can I have a checkbox component that updates an array on the parent? I know I can do this with emitting an event for a method on the component that updates the array but the Vue documentation makes it seems like the framework does this for you.

Here is a code sample I've been playing around with https://www.webpackbin.com/bins/-KwGZ5eSofU5IojAbqU3

1
  • 2
    Please include relevant code in the post itself, not just a link to it. Commented Oct 12, 2017 at 17:50

2 Answers 2

5

Here is a working version.

<template>
  <div class="filter-wrapper">
    <input type="checkbox" v-model="internalValue" :value="value">
    <label>{{label}}</label>
  </div>
</template>

<script>
  export default {
    props: ['checked','value', 'label'],
    model: {
      prop: "checked"
    },
    computed:{
      internalValue: {
        get(){return this.checked},
        set(v){this.$emit("input", v) }
      }
    }
  }
</script>

Updated bin.

Sign up to request clarification or add additional context in comments.

2 Comments

Awesome, thank you for this. Please let me know if I'm understanding how this works. You are creating an internal model for the component and setting it's value to the model that was passed in from the parent. am I understanding this correctly?
@MichaelTurnwall You got it. And when the internal model changes, the change is emitted to the parent.
3

The answer given by @Bert is right. I just want to complete the picture with the list of components and how thay are integrated. As this is a useful pattern.

Also including Select All functionality

ListItem.vue

<template>
    <div class="item">
        <input type="checkbox" v-model="internalChecked" :value="item.id" />

        ... other stuff
    </div>
</template>



<script>
    export default {
        // Through this we get the initial state (or if the parent changes the state)
        props: ['value'],

        computed:{
            internalChecked: {
                get() { return this.value; },

                // We let the parent know if it is checked or not, by sending the ID
                set(selectedId) { this.$emit("input", selectedId) }
            }
        }
  }
</script>

List.vue

<template>
    <div class="list">
        <label><input type="checkbox" v-model="checkedAll" /> All</label>

        <list-item
            v-for="item in items"
            v-bind:key="item.id"

            v-bind:item="item"
            v-model="checked"
        </list-item>

        ... other stuff
    </div>
</template>



<script>
    import ListItem from './ListItem';


    export default {
        data: function() {
            return: {
                // The list of items we need to do operation on
                items: [],

                // The list of IDs of checked items
                areChecked: []
            }
        },


       computed: {
           // Boolean for checked all items functionality
           checkedAll: {
                get: function() {
                    return this.items.length === this.areChecked.length;
                },

                set: function(value) {
                    if (value) {
                        // We've checked the All checkbox
                        // Starting with an empty list
                        this.areChecked = [];
                        // Adding all the items IDs
                        this.invoices.forEach(item => { this.areChecked.push(item.id); });

                    } else {
                        // We've unchecked the All checkbox
                        this.areChecked = [];
                    }
                }
            }
       },


        components: {
            ListItem
        }
  }
</script>

Once boxes get checked we have in checked the list of IDS [1, 5] which we can use to do operation on the items with those IDs

1 Comment

Thank you for this, I believe in your List.vue where you have areChecked it should be checked. Otherwise this worked perfectly.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.