Reputation: 3637
Suppose I have a component with data:
data: function () {
return {
slots: [
{ Id: 1, slotName: 'apple', componentName: 'Apple' },
{ Id: 2, slotName: 'banana', componentName: 'Banana' }
]
}
}
and I want to pass the list of slots as scoped slots to a child component. The following syntax won't work because you cannot use v-for on a template element:
<child-component>
<template v-for="slot in slots" :key="slot.Id" v-slot[slot.slotName]="slotProps">
<component :is="slot.componentName" :someProp="slotProps"></component>
</template>
</child-component>
and the following syntax won't work because in Vue 2.6.0+ any content not wrapped in a <template> using v-slot is assumed to be for the default slot
.
<child-component>
<component v-for="slot in slots" :key="slot.Id"
:is="slot.componentName" v-slot[slot.slotName]="slotProps" :someProp="slotProps"></component>
</child-component>
The following will work but the compiler throws a warning and it uses deprecated syntax:
<child-component>
<component v-for="slot in slots" :key="slot.Id"
:is="slot.componentName" :slot="slot.slotName" slot-scope="slotProps" :someProp="slotProps"></component>
</child-component>
Is there any way to achieve this using non-deprecated Vue template syntax and without using a render function?
Upvotes: 33
Views: 42731
Reputation: 1820
To me, what was really revealling was adding the Dynamic Slot name.
As @Ezequiel Fernandez stated above you could achieve it by:
<template v-slot:[slotName]="slotProps">
<!-- Add Here the content -->
</template>
Here's my example of how to reverse columns where each column was a slot:
<template>
<RowQCardSection subtitle="Subsets">
<template v-slot:[leftCol]>
Label: {{label}}
</template>
<template v-slot:[rightCol]>
<SelectSubsets />
</template>
</RowQCardSection>
</template>
<script setup>
import RowQCardSection from 'src/components/updateTerm/RowQCardSection.vue'
import SelectSubsets from 'src/components/SelectSubsets.vue'
import { computed } from 'vue'
const props = defineProps({
label: String
reverseColumns: {
default: false,
},
})
const leftCol = computed(() => {
return props.reverseColumns ? 'right' : 'left'
})
const rightCol = computed(() => {
return props.reverseColumns ? 'left' : 'right'
})
</script>
Upvotes: 2
Reputation: 1074
You can use v-for into a template component
You just need to specify the key
on the component
.
<child-component>
<template v-for="slot in slots" v-slot:[slot.slotName]="slotProps">
<component :key="slot.Id" :someProp="slotProps"></component>
</template>
</child-component>
Upvotes: 37
Reputation: 476
I had to generate the slot name dynamically. Based on @EzequielFernandez's answer, I did it using a function :
<template v-for="locale in locales" v-slot:[getSlotName(locale)]="slotProps">
...
</template>
data() {
return {
locales: ['en', 'fr']
}
},
methods: {
getSlotName(locale) {
return `locale-${locale}`
}
}
Upvotes: 10