I am trying to apply a transition to a Vuetify v-data-table so that when I delete a tbody in my table, it fades out instead of just vanishing off the screen. If I wrap the tbody in a transition-group the tbody fades out as expected. However, it's wrapped in a span tag which means all of the columns in the tbody get shoved into the first column of my table.
I know I can specify a different tag other than a span, but they all cause my table layout to break. How can I apply a fade transition to the tbody and maintain my table layout?
<v-data-table
ref="dataTable"
:headers="headers"
fixed-header
:height="height"
:items="invoices"
item-key="id"
:search="search"
class="elevation-1"
disable-pagination
:loading="loading"
loading-text="Loading invoices... please wait..."
:no-data-text="this.noDataText"
no-results-text="No invoices found for your search."
:hide-default-footer="true"
>
<template v-slot:headers="props">
<thead>
<tr>
<th
v-for="header in props.headers"
:key="header.text"
ref="dataTableHdr"
:class="['column sortable', pagination.descending ? 'desc' : 'asc', header.value === pagination.sortBy ? 'active' : '', header.class === '']"
@click="changeSort(header.value)"
>
<v-icon small>arrow_upward</v-icon>
{{ header.text }}
</th>
</tr>
</thead>
</template>
<template v-slot:body="{ items }">
<transition-group tag="boo" name="invoice">
<tbody v-for="(item, index) in items" :key="item.id" @click="items.splice(index,1)">
<tr>
<td
:rowspan="updateRowCount(item.invoiceSections)"
valign="top"
class="pt-3 text-left font-weight-medium"
>{{ item.vendorCode }}</td>
<td>CONTENT</td>
<td>CONTENT</td>
<td>CONTENT</td>
<td>CONTENT</td>
<td>CONTENT</td>
</tr>
<tr>
<td>{{ item.vendorName }}</td>
<td>CONTENT</td>
<td>CONTENT</td>
<td>CONTENT</td>
<td>CONTENT</td>
<td>CONTENT</td>
</tr>
</tbody>
</transition-group>
</template>
</v-data-table>
Revised Code:
<template v-slot:body="{ items }">
<tbody v-for="(item, index) in items" :key="item.id">
<transition-group tag="tbody" name="invoice">
<tr key="row1">
<td
:rowspan="updateRowCount(item.invoiceSections)"
valign="top"
class="pt-3 text-left font-weight-medium"
>{{ item.vendorCode }}</td>
<td>CONTENT</td>
<td>CONTENT</td>
<td>CONTENT</td>
<td>CONTENT</td>
<td>
<v-btn @click="reject(items, index)" class="mx-2" v-blur fab small>
<v-icon color="red">mdi-cancel</v-icon>
</v-btn>
</td>
</tr>
<tr key="row2">
<td>{{ item.vendorName }}</td>
<td>CONTENT</td>
<td>CONTENT</td>
<td>CONTENT</td>
<td>CONTENT</td>
<td>CONTENT</td>
</tr>
</transition-group>
</tbody>
</template>
<style>
.invoice-leave-active tr,
.invoice-leave-active tr:hover {
background-color: yellow !important;
}
.invoice-enter-active,
.invoice-leave-active {
transition: opacity 1s;
}
.invoice-enter, .invoice-leave-to /* .invoice-leave-active below version 2.1.8 */ {
opacity: 0;
}
</style>
Here is my final, super complex template, using v-if with changing the item.id to null.
<template v-slot:body="{ items }">
<transition-group tag="tbody" name="invoice" v-for="(item, index) in items" :key="index">
<tr
key="row1"
v-if="item.id"
:class="[item.duplicate ? 'duplicateItemRow' : '', {'success': item.id===selectedId}]"
>
<td
:rowspan="updateRowCount(item.invoiceSections)"
valign="top"
class="pt-3 text-left font-weight-medium"
>{{ item.vendorCode }}</td>
<td
:rowspan="updateRowCount(item.invoiceSections)"
valign="top"
class="pt-3 text-left font-weight-medium"
>{{ item.vendorName }}</td>
<td
:rowspan="updateRowCount(item.invoiceSections)"
valign="top"
class="pt-3 text-left font-weight-medium nowrap"
>{{ item.poNumber }}</td>
<td
:rowspan="updateRowCount(item.invoiceSections)"
valign="top"
class="pt-3 text-left font-weight-medium"
>
<v-tooltip bottom>
<template v-slot:activator="{ on }">
<a
:href="`/rvimain.pgm?rqstyp=senchcall1&isys=a&i7=INV&i4=${item.invoiceNumber}&i6=${item.poNumber}`"
class="pa-0 ma-0"
v-on="on"
target="_blank"
>{{ item.invoiceNumber }}</a>
</template>
<span>Click to view invoice</span>
</v-tooltip>
</td>
<td
:rowspan="updateRowCount(item.invoiceSections)"
valign="top"
class="pt-3 pr-6 text-right font-weight-medium"
>{{ item.invoiceDate | moment("M/D/YYYY") }}</td>
<td :class="item.invoiceAmount !== item.poAmount ? 'amountMismatchItemRow' : ''"></td>
<td
valign="top"
:class="['pt-3', 'font-weight-medium', 'nowrap', item.invoiceAmount !== item.poAmount ? 'amountMismatchItemRow' : '']"
>
<div v-if="item.duplicate">{{ item.duplicate }}</div>
<div
v-if="item.invoiceAmount !== item.poAmount"
>${{ item.poAmount | currency }} PURCHASE ORDER DOES NOT MATCH INVOICE</div>
</td>
<td :class="item.invoiceAmount !== item.poAmount ? 'amountMismatchItemRow' : ''"></td>
<td :class="item.invoiceAmount !== item.poAmount ? 'amountMismatchItemRow' : ''"></td>
<td :class="item.invoiceAmount !== item.poAmount ? 'amountMismatchItemRow' : ''"></td>
<td :class="item.invoiceAmount !== item.poAmount ? 'amountMismatchItemRow' : ''">
<CommentsDialog
v-if="item.invoiceSections[0].comments"
:itemId="item.invoiceSections[0].id"
:comments="item.invoiceSections[0].comments"
/>
</td>
<td
valign="top"
:class="['pt-3', 'text-right', 'font-weight-medium', 'nowrap', item.invoiceAmount !== item.poAmount ? 'amountMismatchItemRow' : '']"
>{{ item.invoiceAmount | currency }}</td>
<td
:rowspan="updateRowCount(item.invoiceSections)"
valign="top"
class="pt-3 text-center"
>
<div v-if="item.approvalDate && !item.rejectedDate">
<v-icon color="green">mdi-check</v-icon>
</div>
<div
v-if="!item.duplicate && !item.approvalDate && !item.rejectedDate && item.invoiceAmount === item.poAmount"
class="mb-4"
>
<v-tooltip bottom>
<template v-slot:activator="{ on }">
<v-btn @click="approveInvoice(item)" v-on="on" v-blur class="mx-2" fab small>
<v-icon color="green">mdi-check</v-icon>
</v-btn>
</template>
<span>Approve invoice</span>
</v-tooltip>
</div>
<RejectButton
v-if="!item.approvalDate && !item.rejectedDate"
:invoice="item"
@removeInvoice="removeInvoice"
/>
<div v-if="!item.approvalDate && item.rejectedDate">
<v-icon color="red" class="mb-4">mdi-cancel</v-icon>
<div>
Rejected
<br />
{{item.rejectedDate | moment("M/D/YYYY")}}
<br />
{{ item.rejectedBy }}
<br />
<RejectReasonDialog
v-if="item.rejectedReason"
:itemId="item.id"
:reason="item.rejectedReason"
/>
</div>
</div>
</td>
</tr>
<!-- SECTIONS -->
<template v-for="(section, index) in item.invoiceSections">
<tr
v-if="item.id && section.length > 0 && section.sectionDescription != ''"
:class="item.duplicate ? 'duplicateItemRow' : 'darkTableRow'"
:key="`${item.id}.${index}`"
>
<td class="text-left" colspan="2">{{ section.sectionDescription }}</td>
<td class="text-left" colspan="3">{{ section.repairReason }}</td>
<td class="text-right nowrap">{{ section.sectionTotal | currency }}</td>
<td>
<CommentsDialog
v-if="section.comments"
:itemId="section.id"
:comments="section.comments"
/>
</td>
</tr>
<!-- ITEMS -->
<tr
:class="[item.duplicate ? 'duplicateItemRow' : '', item.qtyRequested != item.qtyReceived ? 'qtyMismatchItemRow' : '' ]"
v-show="item.id"
v-for="(item, index) in section.invoiceItems"
:key="`${item.id}.${item.id}.${index}`"
>
<td class="text-left">{{ item.partNumber }}</td>
<td class="text-left">{{ item.partDescription }}</td>
<td class="text-right">
<v-tooltip v-if="item.qtyRequested != item.qtyReceived" bottom>
<template v-slot:activator="{ on }">
<span v-on="on" class="help">{{ item.qtyReceived }}</span>
</template>
<span>Requested {{ item.qtyRequested }}</span>
</v-tooltip>
<span v-else>{{ item.qtyReceived }}</span>
</td>
<td
:class="['text-right nowrap nopaddingRight', item.each > item.avgChargeAmount && item.avgChargeAmount != 0 ? 'over help' : '',
item.each < item.avgChargeAmount && item.avgChargeAmount != 0 ? 'under help' : '']"
>
<v-tooltip
v-if="item.each != item.avgChargeAmount && item.avgChargeAmount != 0"
bottom
>
<template v-slot:activator="{ on }">
<span v-on="on">{{ item.each | currency }}</span>
</template>
<span>Avg price: ${{ item.avgChargeAmount | currency }}</span>
</v-tooltip>
<span v-else>{{ item.each | currency }}</span>
</td>
<td
:class="['text-left nowrap lowpaddingLeft', item.each > item.avgChargeAmount && item.avgChargeAmount != 0 ? 'over' : '',
item.each < item.avgChargeAmount && item.avgChargeAmount != 0 ? 'under' : '']"
>
<v-tooltip v-if="item.nationalAccount" bottom>
<template v-slot:activator="{ on }">
<span v-on="on" class="help">N</span>
</template>
<span>
National
<br />Account
</span>
</v-tooltip>
</td>
<td class="text-right nowrap">{{ item.lineTotal | currency }}</td>
<td class="text-left">
<v-btn
outlined
small
color="primary"
dark
v-if="item.comments"
@click.stop="$set(dialogComments, item.id, true)"
>Comments</v-btn>
<CommentsDialog v-if="item.comments" :itemId="item.id" :comments="item.comments" />
</td>
</tr>
</template>
<tr key="row3" v-if="item.id">
<td colspan="13" class="divider"> </td>
</tr>
</transition-group>
</template>
