javascripthtmlvue.jsvuetify.jsv-slot

Vuetify Data Table Expand Row on Column Click


I have a vuetify data table that includes expandable rows. The only real difference I have from the demo is that I would like the item.name column to open/close the expandable row just like the chevron icon. When I put an @click handler on the v-slot for that column I get the error Error in v-on handler: "TypeError: expand is not a function". This is the only column I need to customize so I would like to not have to build out the entire <tr> v-slot by hand. A scaled-down code example is below. Thanks.

<v-data-table
    :headers="headers"
    :items="products"
    item-key="productCode"
    show-expand
    :expanded.sync="expanded"
>

  <template v-slot:item.name="{ item, expand, isExpanded }" >
    <h4 class="my-2" @click="expand(!isExpanded)">{{ item.name }} located in {{ item.depot | camelToWords }}</h4>
  </template>

  <template v-slot:expanded-item="{ headers, item }">
    <ProductDetailExpandedRow :currentProduct="item" :headers="headers"/>
  </template>

</v-data-table>

<script>
export default {
  data() {
    return {
      headers: [
        {
          text: 'Name',
          value: 'name',
        },
        {
          text: 'Product ID',
          value: 'productCode',
        },
        {
          text: 'Stock',
          value: 'stock',
        },
6 more columns continue on here...
      ],
      products: [],
    }
  }
}
</script>

Solution

  • Column click

    Here is how you could do it with a specific column click. Put a @click handler in the column's slot template. This handler receives the column data on click. In this case, the column's name is name:

    <template v-slot:item.name="slotData">
       <div @click="clickColumn(slotData)">{{ slotData.item.name }}</div>
    </template>
    

    Expanded rows are tracked in the expanded array, so add this row's data. But if it's already there, remove it (because then you're trying to collapse an already expanded column)

    clickColumn(slotData) {
      const indexRow = slotData.index;
      const indexExpanded = this.expanded.findIndex(i => i === slotData.item);
      if (indexExpanded > -1) {
        this.expanded.splice(indexExpanded, 1)
      } else {
        this.expanded.push(slotData.item);
      }
    }
    

    Here is the codepen (Rows expand when clicking the first column, within the padding)

    Row click

    Here is how you could do it with a row click (i.e. any column). In the template, add a listener to the <v-data-table> for the click:row event:

    <v-data-table @click:row="clickRow">
    ...
    </v-data-table>
    

    This event passes two arguments: the item, and the item slot data, including the index of the clicked row. Use this information to modify the this.expanded array which tracks all expanded rows:

    clickRow(item, event) {
      if(event.isExpanded) {
        const indexExpanded = this.expanded.findIndex(i => i === item);
        this.expanded.splice(indexExpanded, 1)
      } else {
        this.expanded.push(item);
      }
    }
    

    This adds the item to the expanded array or it removes it by finding the index and using splice.

    Here is the codepen (Rows expand when clicking anywhere in the row)