[Vuejs]-How to select checked checkboxes inside multiple divs with VueJS

0👍

You need to listen for events on your base-checkbox components and update suitable data structures accordingly. In Vue the DOM is secondary, your primary source of truth is in JavaScript data.

There are many different ways to approach this depending on what data structures make most sense in a given scenario. To quote The Mythical Man-Month:

Representation is the essence of programming.

With that in mind, I’m not convinced that the example I’ve constructed below is necessarily using the best data structures to represent the data, or even that I’m using those data structure as well as they can be used.

Some notes:

  • The computed property out holds the data in the finished format, the one used when the submit button is clicked. I haven’t included a submit button, I’ve just dumped that data out so you can see it.
  • Keeping paths and selectedPaths separate is not strictly required but it seemed closer to your original code, with paths being analogous to newProfile.paths.
  • The format within selectedPaths is {path1: {add: true, edit: false, delete: true}, path2: ...}. The properties are created lazily, defaulting to all checkboxes being false.
  • Because selectedPaths is initially created empty its properties won’t be reactive. That’s why $set is being used. If it were possible to prepopulate this object within the data method it wouldn’t be necessary to use $set.
  • I’ve used HTML <input> elements for my checkboxes but the approach would be exactly the same with a checkbox component. A prop passes in the current value and an event is used to update the data when the value changes.
  • When using a v-for like this, it’s often simpler to split off a separate child component for the children. Rather than manipulating complex data structures in the parent, some of the work can be offloaded onto each child. I haven’t done that here as I was trying to keep everything within one component but it is something I would explore if I were doing this for real.
<template>
    <div>
        <ul>
            <li v-for="path in pathsWithSelections" :key="path.path">
                {{ path.path }}
                <input type="checkbox" :checked="path.add" @input="onChecked(path.path, 'add')">
                <input type="checkbox" :checked="path.edit" @input="onChecked(path.path, 'edit')">
                <input type="checkbox" :checked="path.delete" @input="onChecked(path.path, 'delete')">
            </li>
        </ul>
        {{ out }}
    </div>
</template>

<script>
    export default {
        data () {
            return {
                paths: ['path1', 'path2', 'path3'],
                selectedPaths: {}
            }
        },

        computed: {
            pathsWithSelections () {
                return this.paths.map(path => {
                    const selected = this.selectedPaths[path] || {}

                    return {
                        path,
                        ...selected
                    }
                })
            },

            out () {
                const out = []

                for (const path of this.pathsWithSelections) {
                    const actions = []

                    for (const action of ['add', 'edit', 'delete']) {
                        if (path[action]) {
                            actions.push(action)
                        }
                    }

                    if (actions.length) {
                        out.push({
                            path: path.path,
                            actions
                        })
                    }
                }

                return out
            }
        },

        methods: {
            onChecked (path, action) {
                const selectedPaths = this.selectedPaths

                const selected = selectedPaths[path] || {}

                this.$set(selectedPaths, path, selected)
                this.$set(selected, action, !selected[action])
            }
        }
    }
</script>

Leave a comment