Vue.js - Dynamically create slots from filtered scopedSlots

Viewed 722

Thanks to Vue.js Scoped Slots, I'm able to loop over all available slots in the Child component. Now, what I try to do is to render only the slots beginning with a certain string on a specific place in the template.

Unfortunately, it doesn't work. I'm probably overlooking something.

Parent.vue:

<Child>
    <template #table--item.person_id="{ value }">
        <div class="text-caption">{{ value }}</div>
    </template>
</Child>

Child.vue:

<template>
    <v-data-table>
        <template v-for="(_, slotName) of tableSlots" v-slot:[slotName]="scope">
            <slot :name="slotName" v-bind="scope"></slot>
        </template>
    </v-data-table>
</template>
<script>
    export default {
        computed: {
            tableSlots() {
                const prefix = 'table--';
                const raw = this.$scopedSlots;
                const filtered = Object.keys(raw)
                    .filter(key => key.startsWith(prefix))
                    .reduce((obj, key) => ({
                        ...obj,
                        [key.replace(prefix, "")]: raw[key]
                    }), {});
                return filtered;
            }
        }
    }
</script>

https://codesandbox.io/s/keen-bose-yi8x0

1 Answers

The parent tries to access a slot named table--item.glutenfree and so a scoped slot is created with that name. But when you filter in order to target the corresponding v-data-table slot, you also use that filtered name for the child slot:

key.replace(prefix, "")

The parent can't access the child slot because the parent is targeting a name with the prefix still intact.

Change the slot in the child component:

<slot :name="`table--${slotName}`" v-bind="scope"></slot>
Related