2
votes

I'm trying to create a reusable table component that utilizes Vuetify's v-data-table component in order to group common aspects such as a search bar, table actions (refresh, create, etc.) and other features that all of my tables will have. However, I'm running into issues with implementing dynamic, scoped slots inside the table component to account for custom columns. Think of columns like actions, formatted ISO strings, etc.

Here's a simplified example of what I'm trying currently. In the example, I am passing the array customColumns to CustomDataTable.vue as a prop. customColumns has one element with two properties. The slotName property specifies the name of the slot that I'd like to reference in the parent component. The itemValue property specifies the header value that CustomDataTable.vue should override and replace with a scoped slot. The scoped slot is then used in the parent component to correctly format the date in the 'Created At' column.

Parent Component that is implementing the table component:

<template>
  <custom-data-table
    :items="items"
    :headers="headers"
    :customColumns="customColumns"
  >
    <template v-slot:custom-column="slotProps">
      <span>{{ formatDate(slotProps.item.createdAt) }}</span>
    </template>
  </custom-data-table>
</template>

<script>
import CustomDataTableVue from '@/components/table/CustomDataTable.vue'

export default {
  data: () => ({
    items: [
      {
        id: 0,
        createdAt: new Date().toISOString(),
        ...
      },
      ...
    ],
    headers: [
      {
        text: 'Created At',
        value: 'createdAt',
        sortable: true
      },
      ...
    ],
    customColumns: [
      {
        slotName: 'custom-column',
        itemValue: 'createdAt' 
      }
    ]
  })
}
</<script>

CustomDataTable.vue

<template>
  <v-data-table
    :items="items"
    :headers="headers"
  >
    <template v-for="column in customColumns" v-slot:item[column.itemValue]="{ item }">
      <slot :name="column.slotName" :item="item"/>
    </template>
  </v-data-table>
</template>

<script>
export default {
  name: 'custom-data-table',

  props: {
    items: {
      type: Array,
      required: true
    },
    headers: {
      type: Array,
      required: true
    },
    customColumns: {
      type: Array
    }
  }
}
</<script>

Is there a way to achieve this? The example does not override the column values and just displays the createdAt ISO string unformatted. I believe the problem might be coming from how I'm assigning the template's slot in CustomDataTable.vue, but I'm sure how else you could dynamically specify a template's slot. Any ideas?

1

1 Answers

4
votes

I think the syntax for dynamic slots should be:

 <template 
     v-for="column in customColumns" 
     v-slot:[`item.${column.itemValue}`]="{ item }"
 >
       <slot :name="column.slotName" :item="item"/>
</template>