Search code examples
javascriptvue.jsvuetify.jsweb-frontend

Vuetify 2, Is there a way to make the items inside the expansion for a v-data-table match the headers for the root component?


I am trying to render a v-data-table with a "panel" title as the expandable section of a v-data-table, and would like the data inside the expansion to align with the headers that I have set on the root. So far, I have found no way in the Vuetify documentation or in trial and error to do this, I have had to resort to putting the headers inside the expansion for alignment. This will work as a secondary option, but I just know there has to be a way to do the first.

I am trying to match what would be in this image:enter image description here

The code for what I have for the headers inside the expansion is as follows:

`<template>
    <v-data-table
        :headers="panelHeaders"
        :items="panels"
        item-key="panel"
        show-expand
        :expanded.sync="expandedItems"
    >
        <template v-slot:[`item.panel`]="{ item }">
            {{ item.panel }}
        </template>
        <template v-slot:expanded-item="{ headers, item }">
            <td :colspan="headers.length">
                <v-data-table
                    :headers="expandedPanelHeaders"
                    :items="item.vendors"
                >
                    <v-row v-for="(expandedVendor, vendorIndex) in item.vendors" :key="vendorIndex">
                        <template  v-slot:item="{ item }">
                            <td>
                                <p>notes here</p>
                            </td>
                            <td>
                                <span>{{ expandedVendor.name }}</span>
                            </td>
                            <td>
                                <span>{{ expandedVendor.status }}</span>
                            </td>
                            <td>
                                <span>{{ expandedVendor.distance }}</span>
                            </td>
                            <td>
                                <span>{{ expandedVendor.on_time }}</span>
                            </td>
                            <td>
                                <v-chip-group column>
                                    <v-chip
                                        v-for="(tag, tagIndex) in expandedVendor.vendor_tags"
                                        :key="tagIndex"
                                        :color="tag.color"
                                    >
                                        {{ tag.tag }}
                                    </v-chip>
                                </v-chip-group>
                            </td>
                            <td>
                                <v-btn>Assign</v-btn>
                            </td>
                        </template>
                    </v-row>
                </v-data-table>
            </td>
        </template>
    </v-data-table>
</template>

<script lang="ts">
import { defineComponent, ref } from '@vue/composition-api'
import { order } from '@/plugins/order/Order'
import { PanelData } from "@/types";

/**
 * @name AssignPanels
 *
 */

export default defineComponent({
    props:{
        panels: {
            default: () => [],
            type: Array as () => PanelData[]
        }
    },
    setup() {
        const panelHeaders = ref([
            { text: 'Panel', value: 'panel', sortable: false, align: 'start'},
        ])

        const expandedPanelHeaders = ref([
            {text: 'Notes', sortable: false, value: 'notes'},
            {text: 'Name', sortable: false, value: 'name'},
            {text: 'Assign Status', sortable: false, value: 'assign_status'},
            {text: 'Distance', sortable: false, value: 'distance'},
            {text: 'On-Time %', sortable: false, value: 'on_time'},
            {text: 'Tags', sortable: false, value: 'tags'},
            {text: 'Assign', sortable: false, value: 'assign_action'},
        ])

        const expandedItems = ref([])


        return {
            panelHeaders,
            expandedPanelHeaders,
            expandedItems,
            order,
        }
    },
})
</script>

`

Any help or advice would be greatly appreciated, I am fairly new to front end development and am eager to find a better way to do this.


Solution

  • Hmm, closest option is probably to use grouping.

    Override the default group header to remove the button that undoes grouping.

    However, there is no way to close groups initially.

    new Vue({
      el: '#app',
      vuetify: new Vuetify(),
      template: `
        <v-app>
          <v-main>
            <v-container>
            
        <v-data-table
            :headers="headers"
            :items="items"
            group-by="panel"
            mobile-breakpoint="0"
            :expanded="[]"
        >
         <template #group.header="{group, groupBy, toggle, isOpen, headers}">
            <td :colspan="headers.length">
              <v-btn icon @click="toggle">
                <v-icon>mdi-{{isOpen ? 'minus' : 'plus'}}</v-icon>
              </v-btn> 
              Custom Panel {{group}}
            </td>
         </template>
        </v-data-table>
            
            </v-container>
          </v-main>
        </v-app>
      `,
      data(){
        return {
          headers: [
              {text: 'Panel', value: 'panel'},
              {text: 'Notes', value: 'notes'},
              {text: 'Name', value: 'name'},
          ],
          items: Array.from({length: 10}, (_,i) => ({
            id: i, 
            name: 'Han Solo', 
            panel: i/3|0, 
            notes: Math.random()*20|0,
          }))
        }
      }
    })
    <link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
    <link href="https://cdn.jsdelivr.net/npm/@mdi/[email protected]/css/materialdesignicons.min.css" rel="stylesheet">
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.min.css" rel="stylesheet">
    
    <div id="app"></div>
    
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.js"></script>