0
votes

Does anyone know how to pass dynamic slots from parent down to grandchild?

I know how to do it with static named slots but not with dynamic named slots.

For example, let's say the slot template is 'name' in the parent and the grandchild has the slot based on dynamic columns.

How do I add a template in the child to pass this down.

Here is an example of my code:

// GrandChild.vue

<template>
    <table>
        <tbody>
            <template v-for="(item, itemIndex) in items">
                <tr :key="itemIndex">
                    <template v-for="(col, colIndex) in columns">
                        <slot
                          v-if="$scopedSlots[col]"
                          :name="col"
                          :item="item"
                        />
                        <td
                          v-else
                          :key="colIndex"
                        >
                          {{ String(item[col]) }}
                        </td>
                    </template>
                </tr>
            </template>
        </body>
    </table>
</template>

<script>
    export default {
        props: ['items', 'columns']
    }
</script>
// Child.vue

<template>
    <grand-child :items="items" :columns="columns">
        <!-- not sure what goes here -->
    </grand-child>
</template>

<script>
    export default {
        props: ['items', 'columns']
    }
</script>
// Parent.vue

<template>
    <child :items="items" :columns="columns">
        <template #name="{item}">
            <td>Name is {{ item.name }}</td>
        </teamplate>
    </child>
</template>

<script>
    export default {
        data () {
            return {
                items: [
                    {id: 1, name: 'Item 1'},
                    {id: 2, name: 'Item 2'},
                    {id: 3, name: 'Item 3'},
                    {id: 4, name: 'Item 4'}
                ],
                columns: ['id', 'name']
            }
        }
    }
</script>

Any help appreciated.

1

1 Answers

2
votes

I have worked it out. I will answer my own question in case it can help someone else in the future.

To bridge the parent and grandchild, I put the following in the intermediate component (in my case Child.vue)

<template v-for="field in Object.keys($scopedSlots)" v-slot:[field]="{item}">
    <slot :name="field" :item="item"/>
</template>

Full code:

// Child.vue

<template>
    <grand-child :items="items" :columns="columns">
        <template v-for="field in Object.keys($scopedSlots)" v-slot:[field]="{item}">
            <slot :name="field" :item="item"/>
        </template>
    </grand-child>
</template>

<script>
    export default {
        props: ['items', 'columns']
    }
</script>