16
votes

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?

1
You can use v-for into a template component vuejs.org/v2/guide/list.html#v-for-on-a-lt-template-gtEzequiel Fernandez
@EzequielFernandez You are right! When I tried this I got a compiler error about not being allowed to key <template> elements, but we can key the <component> instead.Daniel Elkington
@DanielElkington cool!Ezequiel Fernandez
@YomS. The props are being injected by child-component. Each slot needs them.Daniel Elkington

1 Answers

14
votes

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>