Search code examples
vue.jsdatatablevuetify.js

I want to have icon besides item in a datatable depending on what the item is. For example if the item is a pdf I want a pdf icon next to it


So I have a set of headers in a manifest.json that im fetching in my Vue app. I want it to be an table with headers and one expandable header for icons to the left of the table. The icon is suppose to change depending of the type of content. The problem is that the icon is not being viseble to the left. And if i put it to the very right of the table the "expand-tablebutton" disapears.

  | Title        | Type      | Source  | Location    |
    |--------------|-----------|---------|-------------|
icon| Harry Potter | PDF       | Amazon  | London      |expand
icon| Avengers     | WORD      | Netflix | New York    |expand
icon|              | PDF       | HBO     | Los Angeles |expand

I want it to look like that. But right now the icons are not viseble.

<template v-slot:expanded-row="{ columns, item }">
  <tr>
    <td class="icon-column">
      <v-icon icon="mdi-file-pdf-box"></v-icon>
    </td>
    <td class="expandable-data" :colspan="columns.length - 1">
      <div class="expandable-dta">
        <!-- your expandable content here -->
      </div>
    </td>
  </tr>
</template>

How should i fix this?


Solution

  • You can add a dummy-column to your headers, key does not have to exist on the item:

    const headers = ref([
      {key: 'row-icon', title: ''}, 
      ...
    }],
    

    Then you just have to add an item slot where you set the icon:

    <template v-slot:item.row-icon="{item}">
      <v-icon>{{ getIconForItem(item) }}</v-icon>
    </template>
    

    If you run into problems with the position of the expand button, try moving it by adding a header with key data-table-expand:

    const headers = ref([
      {key: 'data-table-expand', title: ''}, //<--- first column will contain expand button
      ...
    }],
    

    Have a look at the snippet:

    const { createApp, ref } = Vue;
    const { createVuetify } = Vuetify
    const vuetify = createVuetify()
    const app = {
      setup(){
        const items = ref(Array.from({length:10}, (_,i) => ({
          id: 1 + i, 
          name: `Item ${1 + i}`
        })))
    
        return {
          headers: [{key: 'row-icon', title: '', width: '48'}, {key: 'data-table-expand'}, {key: 'id', title: 'ID'},{key: 'name', title: 'Name'}],
          items,
        }
      },
    }
    createApp(app).use(vuetify).mount('#app')
    <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/vuetify@3/dist/vuetify.min.css" />
    <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/vuetify@3/dist/vuetify-labs.min.css" />
    <link href="https://cdn.jsdelivr.net/npm/@mdi/font@5.x/css/materialdesignicons.min.css" rel="stylesheet">
    <div id="app">
      <v-app>
        <v-data-table
        :headers="headers"
        :items="items"
        item-title="name"
        item-value="name"
        show-expand
      >
        <template v-slot:item.row-icon="{item}">
          <v-icon color="primary">{{ item.raw.id %2 === 0 ? 'mdi-cow' : 'mdi-pig'}}</v-icon>
        </template>
        
        <template v-slot:expanded-row="{ columns, item }">
          <tr>
            <td :colspan="columns.length">
              expanded content
            </td>
          </tr>
        </template>
      </v-data-table>
      </v-app>
    </div>
    <script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vuetify@3/dist/vuetify.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vuetify@3/dist/vuetify-labs.js"></script>