2

сеI have an array with categories. Each category has children.

When a parent is checked/unchecked, its children must be checked/unchecked as well. If all children are checked, the parent must be checked as well.

Vue updates the fields as expected, but doesn't re-render. I cannot understand why.

Here is my code:

<template>
    <div class="card">
            <div class="card-body">
                    <ul class="list-tree">
                        <li v-for="category in categories" :key="category.id" v-show="category.show">
                            <div class="custom-control custom-checkbox">
                                <input :id="'category-' + category.id"
                                             v-model="category.checked"
                                             @change="checkParent(category)"
                                             type="checkbox"
                                             class="custom-control-input" />
                                <label class="custom-control-label"
                                             :for="'category-' + category.id">
                                    {{ category.name }}
                                </label>
                            </div>
                            <ul>
                                <li v-for="child in category.children" :key="child.id" v-show="child.show">
                                    <div class="custom-control custom-checkbox">
                                        <input :id="'category-' + child.id"
                                                     v-model="child.checked"
                                                     @change="checkChild(child, category)"
                                                     type="checkbox"
                                                     class="custom-control-input" />
                                        <label class="custom-control-label" :for="'category-' + child.id">
                                            {{ child.name }}
                                            <small class="counter">({{ child.products_count }})</small>
                                        </label>
                                    </div>
                                </li>
                            </ul>
                        </li>
                    </ul>
                </div>
    </div>
</template>

export default {

    data () {
        return {
            categories: [],
            listItemTemplate: { show: true, markedText: null, checked: false }
        }
    },

    methods: {

        checkParent (category) {
            category.children.forEach(child => {
                child.checked = category.checked
            })
        },            

        initializeCategories () {
            this.categories = []

            this.originalCategories.forEach(originalCategory => {
                var parent = this.copyObject(originalCategory)

                this.categories.push(parent)

                parent.children.forEach (child => {
                    child = this.copyObject(child)
                })
            })
        },

        copyObject (category) {
           return Object.assign(category,   {...this.listItemTemplate})
        }
    },

    computed: {
        ...mapState({
             originalCategories: state => state.categories,
        })

     },

     mounted () {
        this.initializeCategories()
     }

}

2 Answers 2

1

You need to expand your scope, since you are changing it only within checkParent() method, variables that you are making changes to will not have an effect onto components variables.

Use the index instead of value in categories iteration to find correct category, and then apply changes in scope of whole component:

<li v-for="(category, categoryIndex) in categories" :key="category.id" v-show="category.show">
     <div class="custom-control custom-checkbox">
                                    <input :id="'category-' + category.id"
                                                 v-model="category.checked"
                                                 @change="checkParent(categoryIndex)"
                                                 type="checkbox"
                                                 class="custom-control-input" />
                                    <label class="custom-control-label"
                                                 :for="'category-' + category.id">

                                    {{ category.name }}     
                     </label>
              </div> <!-- the rest of the code ... -->

And then in component's method:

methods: {

    checkParent (categoryIndex) {
       let categoryChecked = this.categories[categoryIndex];
        this.categories[categoryIndex].children.forEach((child, childIndex) => {
            this.categories[categoryIndex].children[childIndex].checked = categoryChecked;
        })
    },     
Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for your response. Unfortunately this does not work :(
0

I fixed it. The problem wasn't related to the checkboxes at all. The problem was related to the way I've created the categories array.

When I initialize the component, I copy the array from vuex and add new properties (like checked) in order to check the children when the parent is checked. I didn't follow the rules for adding new fields, that's why the children wasn't reactive and didn't get checked when the parent was checked.

Thanks a lot for your effort to help me!

Comments

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.