简体   繁体   中英

How to sync checkboxes between Vue 3 parent and child components

I have a Vue 3 InertiaJS app that contains a parent/child set of components where the parent component contains a form, along with a child component that searches for users and displays the results in a table where each row has a checkbox, so I can select users and then submit them as part of the form. What I need to do is sync the parent component with the checkbox values from the child component. Here is what I have.

Create.vue

<script setup>
    import {Inertia} from '@inertiajs/inertia';
    import {ref} from 'vue';
    import {Head, Link, useForm} from '@inertiajs/inertia-vue3'

    const form = useForm({
        name: '',
        checkedNames: []
    });
    const checkedNames = ref([])
    const props = defineProps({
        users: Object
    })
    </script>
    <template>
        <area-user-select
            :users="props.users"
            @searchUsers="searchUsers"
            v-model:checkedNames="checkedNames"
        ></area-user-select>
    </template>

AreaUserSelect.vue (child component)

<script setup>
    import { Head } from '@inertiajs/inertia-vue3';
    import Icon from '@/Components/Icon.vue';
    import {ref} from 'vue';

    const props = defineProps({
        users: Object,
        filters: Object,
        checkedNames: Array
    })

</script>

<template>
    <div>
    ...
        <div v-if="users.data.length > 0">
            <table class="table-auto">
                <thead>
                <tr class="text-left font-bold">
                    <th class="pb-4 pt-6 px-6 text-sm">Select</th>
                    <th class="pb-4 pt-6 px-6 text-sm">Name</th>
                    <th class="pb-4 pt-6 px-6 text-sm">Last Name</th>
                    <th class="pb-4 pt-6 px-6 text-sm">Member Number</th>
                    <th class="pb-4 pt-6 px-6 text-sm">Status</th>
                </tr>
                </thead>
                <tbody>
                <tr v-for="user in users.data" :key="user.id" class="hover:bg-gray-100 focus-within:bg-gray-100">
                    <td class="border-t">
                        <input
                            type="checkbox"
                            name="selected"
                            :value="user.id"
                            @input="$emit('update:checkedNames', $event.target.value)"
                        />
                    </td>
                    <td class="border-t">
                            {{ user.first_name }}
                    </td>
                    <td class="border-t">
                            {{ user.last_name }}
                    </td>
                    <td class="border-t">
                            {{ user.member_number }}
                    </td>
                    <td class="border-t">
                            {{ user.status }}
                    </td>
                </tr>
                </tbody>
            </table>
        </div>
    </div>
</template>

This works, sort of. In my parent component, if I display the value of checkedName it only contains the value of the last item checked, not an array of all selected values.

What do I need to change so that all selected items are synced back to the parent ( Create.vue ) component?

You can do it this way:

Bind your parent to your component with 'v-model':

<my-component ... v-model="checkedNames"/>

Docs: Component v-model

Bind your checkboxes to a internal component property:

<input type="checkbox" ... v-model="checked" /> 

Docs: Form Input Bindings - Checkbox

End send updates with watch to the parent:

 watch(checked, (newVal) => { emit('update:modelValue', newVal) });

Docs: Watchers

Here is the playground:

 const { createApp, ref, watch } = Vue; const users = [ { id: 1, name: "User 1" }, { id: 2, name: "User 2" } ]; const myComponent = { props: ['items'], emits: ['update:modelValue'], setup(props, { emit }) { const checked = ref([]); watch(checked, (newVal) => { emit('update:modelValue', newVal) }); return {emit, checked} }, template: '#my-checkbox' } const App = { components: { myComponent }, setup() { const checkedNames = ref([]); const setCheckedNames = (newVal) => checkedNames.value = newVal; return { users, checkedNames, setCheckedNames } } } const app = createApp(App) app.mount('#app')
 <div id="app"> Checked: {{checkedNames}}<br /><br /> <my-component:items="users" v-model="checkedNames"/> </div> <script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script> <script type="text/x-template" id="my-checkbox"> <div v-for="user in items"> <input type="checkbox" name="selected":value="user.id" v-model="checked" /> <label>{{user.name}}</label> </div> </script>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM