Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to declare a list of slots with dynamic names and dynamic components in a VueJS template?

Tags:

vue.js

vuejs2

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?

like image 522
Daniel Elkington Avatar asked Jul 23 '19 04:07

Daniel Elkington


People also ask

How do you use Vue slots?

How to use it. Using the slot is very easy, we should just write the <slot> component (which is a reserved word in Vue. js) inside the child component's template, where we want to receive data. A child component uses slot.

What are Vue dynamic components?

Vue dynamic components enable users to switch between two or more components without routing, and even retain the state of data when switching back to the initial component. The central idea is to let users dynamically mount and unmount components in the user interface without using routers.

How do you use named slots?

There are two steps to using named slots in Vue: Naming our slots from our child component using the name attribute. Providing content to these named slots from our parent component using the v-slot directive.

What is slotProps?

slotProps is just a variable we used to access the props we passed. You can also avoid setting a variable just to hold the props you pass to the child component, by destructuring the object on the fly: <page> <template v-slot="{ dogName }"> {{ dogName }} </template> </page>


2 Answers

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>
like image 71
Ezequiel Fernandez Avatar answered Oct 26 '22 03:10

Ezequiel Fernandez


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}`
  }
}
like image 38
Victor Weiss Avatar answered Oct 26 '22 04:10

Victor Weiss