Screeaam
Screeaam

Reputation: 31

Vuetify access v-slot:item in datatable custom component

I've made a custom datatable component, where my Table.vue file is shown below:

<template>
    <div>
        <v-data-table
            :headers="headers"
            :items="items"
            :search="search"
            :loading="loading"
            loading-text="Loading... Please wait"
            dense
            >
            <template v-slot:top>
                <v-toolbar dark flat dense>
                    <v-toolbar-title>{{ title }}</v-toolbar-title>
                    <v-spacer></v-spacer>
                    <v-text-field
                        v-model="search"
                        append-icon="mdi-magnify"
                        label="Search"
                        single-line
                        hide-details
                        ></v-text-field>
                    <v-spacer></v-spacer>
                </v-toolbar>
            </template>
        </v-data-table>
    </div>
</template>

<script>
    export default {
        name: "Table",
        props: [
            "headers",
            "items",
            "title",
            "itemsPerPage",
            "loading",
        ],
        data: function () {
            return {
                search: '',
            }
        },
        methods: {
        },
    };
</script>

And I'm using it like that:

<Table
    :headers="headers"
    :items="groups"
    :loading="loading"
    title="Baseny"
    >
</Table>

Everything is fine, but I want to add custom columns with actions for every input (every input has different ID)

Normally (without a custom component) I'd use the following code:

<v-data-table
   :headers="headers"
   :items="times"
   :items-per-page="5"
   :search="search"
   :loading="loading"
   loading-text="Ładowanie... Proszę czekać"
>

            <template v-slot:top>
                <v-toolbar dark flat dense>
                    <v-toolbar-title>Lista zajęć</v-toolbar-title>
                    <v-spacer></v-spacer>
                    <v-text-field
                        v-model="search"
                        append-icon="mdi-magnify"
                        label="Szukaj"
                        single-line
                        hide-details
                        ></v-text-field>
                    <v-spacer></v-spacer>
                    <v-btn
                        color="primary"
                        :to="{ name: 'admin.times.create' }"
                        >
                        Dodaj zajęcie
                    </v-btn>
                </v-toolbar>
            </template>

            <template v-slot:item.actions="{ item }">
                <v-icon
                    small
                    class="mr-2"
                    @click="show(item)"
                    >
                    mdi-pool
                </v-icon>
                <v-icon
                    small
                    class="mr-2"
                    @click="edit(item)"
                    >
                    mdi-pencil
                </v-icon>
            </template>

</v-data-table>

I'm using this v-slot:

<template v-slot:item.actions="{ item }">
                <v-icon
                    small
                    class="mr-2"
                    @click="show(item)"
                    >
                    mdi-pool
                </v-icon>
                <v-icon
                    small
                    class="mr-2"
                    @click="edit(item)"
                    >
                    mdi-pencil
                </v-icon>
</template>

However, when I wrote the custom reusable table components it didn't work when I put these lines into tag.

How can I use my custom components properly in this scenario?

Upvotes: 0

Views: 3238

Answers (1)

Hammerbot
Hammerbot

Reputation: 16344

What you want to achieve is I believe a wrapper component. You want to wrap a component on top of another one to let him have some custom properties that you want to reuse in your application.

What you need is a small snippet that will allow your slots to be used:

<!-- pass through scoped slots -->
<template v-for="(_, scopedSlotName) in $scopedSlots" v-slot:[scopedSlotName]="slotData">
  <slot :name="scopedSlotName" v-bind="slotData" />
</template>

<!-- pass through normal slots -->
<template v-for="(_, slotName) in $slots" v-slot:[slotName]>
  <slot :name="slotName" />
</template>

You can find the source of this here

Basically, here how you can rewrite your CustomTable.vue:

<template>
  <div>
    <v-data-table
      v-bind="$attrs"
      v-on="$listeners"
      :search="search"
      loading-text="Loading... Please wait"
      dense
    >
      <!-- pass through scoped slots -->
      <template
        v-for="(_, scopedSlotName) in $scopedSlots"
        v-slot:[scopedSlotName]="slotData"
      >
        <slot :name="scopedSlotName" v-bind="slotData" />
      </template>

      <!-- pass through normal slots -->
      <template v-for="(_, slotName) in $slots" v-slot:[slotName]>
        <slot :name="slotName" />
      </template>
      <template v-slot:top>
        <v-toolbar dark flat dense>
          <v-toolbar-title>{{ title }}</v-toolbar-title>
          <v-spacer></v-spacer>
          <v-text-field
            v-model="search"
            append-icon="mdi-magnify"
            label="Search"
            single-line
            hide-details
          ></v-text-field>
          <v-spacer></v-spacer>
        </v-toolbar>
      </template>
    </v-data-table>
  </div>
</template>

<script>
export default {
  name: "CustomTable",
  props: ["title"],
  data: function () {
    return {
      search: "",
    };
  },
  methods: {},
};
</script>

I made a codesandbox to show you how it works: https://codesandbox.io/s/vuetify-2-forked-3lp9y?file=/src/components/CustomTable.vue

I also added automatic attribute and listeners bindings on your table, to allow you to use all the features that Vuetify provides.

Upvotes: 5

Related Questions