6
votes

I have a Vuetify data table with expandable rows. Each row correlates with a customer's order which consists of samples they want to be tested.

Currently, I'm retrieving all the orders with all the samples but it takes too long to load all the information.

So instead of retrieving all the samples for every order, when I expand a row I want to be able to perform an API call to retrieve the samples that should be displayed in the expanded section for that particular order.

I've researched all I can and have come to a dead-end. Here's where I'm at currently:

<v-data-table
  :headers="orders_headers"
  :items="orders"
  show-expand
  :single-expand="true"
  :expanded.sync="expanded"
>

  <!-- Expand Buttons -->
  <template v-slot:item.data-table-expand="{ item, isExpanded, expand }">
    <v-btn @click="expand(true)" v-if="!isExpanded">Expand</v-btn>
    <v-btn @click="expand(false)" v-if="isExpanded">close</v-btn>
  </template>

  <!-- Expanded Data -->
  <template v-slot:expanded-item="{ headers, item }">
    <td :colspan="headers.length">

      <table v-for="(sample, index) in item.samples" :key="index">
        <tr>
          <th>Sample Acc</th>
          <td>{{ sample.sample_accession }}</td>
        </tr>
        <tr>
          <th>Sample Status</th>
          <td>{{ sample.sample_status }}</td>
        </tr>
      </table>

    </td>
  </template>
</v-data-table>

I think I may have figured it while writing this

As I was typing this out, I realized what I possibly need to do. I need to add a method call to the expand button, then in that method set the results to expandedSamples and replace item.samples with it.

In the meantime, if anyone has any better solution I'd love to hear. Otherwise, I'll post my solution in case anyone else is trying to attempt something similar to this.

Bonus

Anyone know if there's a way to tap into the expand event without replacing the default icons/functionality or a way to include the original icons/functionality when using v-slot:item.data-table-expand?

Currently when I'm using v-slot:item.data-table-expand, I have to add the buttons back in and I lose the chevrons and the animations.

2
You're on the right track. You should catch the expand event and fetch the data. Then populate the item.Radu Diță
Hoping for an answer on the bonus question too. I just want to change the color of the chevron icons but I can't find the original code for what was inside v-slot:item.data-table-expandJonathan Lee

2 Answers

6
votes

For the benefit of future readers facing the same issue, use the @item-expanded event of the data-table to lazy load the item details (or child data) on demand. Hook the item-expanded event to a method (e.g. loadDetails) that loads the data, and then merges the response into the original items array.

Here's an example...

  <v-data-table
    :headers="headers"
    :items="items"
    show-expand
    single-expand
    item-key="name"
    :search="search"
    @item-expanded="loadDetails">
    <template v-slot:expanded-item="{ headers, item }">
        <td :colspan="headers.length">
           <table v-for="(sample, index) in items.samples" :key="index">
            <tr>
              <th>Sample Acc</th>
              <td>{{ sample.sample_accession }}</td>
            </tr>
           </table>
        </td>
    </template>
  </v-data-table>

  methods: {
    loadDetails({item}) {
        axios.get('http.../' + item.id)
            .then(response => {
              item.samples = response.data[0]
        })
    }
  }

https://codeply.com/p/d5XibmqjUh

0
votes

Here's the basic solution to my issue.

<v-data-table
  :headers="orders_headers"
  :items="orders"
  show-expand
  :single-expand="true"
  :expanded.sync="expanded"
>

  <!-- Expand Buttons -->
  <template v-slot:item.data-table-expand="{ item, isExpanded, expand }">
    <v-btn @click="expand(true); getSamples(item.id)" v-if="!isExpanded">Expand</v-btn>
    <v-btn @click="expand(false)" v-if="isExpanded">close</v-btn>
  </template>

  <!-- Expanded Data -->
  <template v-slot:expanded-item="{ headers, item }">
    <td :colspan="headers.length">

      <table v-for="(sample, index) in expandedOrderDetails" :key="index">
        <tr>
          <th>Sample Acc</th>
          <td>{{ sample.sample_accession }}</td>
        </tr>
        <tr>
          <th>Sample Status</th>
          <td>{{ sample.sample_status }}</td>
        </tr>
      </table>

    </td>
  </template>
</v-data-table>

<script>
methods: {
  getSamples(orderId) {
    // Perform API call
    this.expandedOrderDetails = response.data;
  },
}
</script>

After many hours of development, our project leader has decided he wants each row to correlate to each sample instead of orders though. So expanding is no longer necessary.