Hi I'm trying to add a css transition on a expanded row using the vuetify 3 v-data-table component inside a ui-template in Dashboard 2.0. I click anywhere on the row to expand the row for more information. All of that works great, but I can't get a smooth transition to happen. I've tried several props, v-expand-transition. I used the v-bind:class to dynamically add a class name and used CSS to do the transition or animation. The expanded component opens and closes with no problem, but no transition.
NR version: 3.1.5
Dashboard 2.0 version: 1.4.1
Here's my code
<template>
<v-data-table :headers="visibleHeaders" :items="items" :items-per-page="itemsPerPage" class="elevation-1"
v-model:expanded="expanded" item-key="id">
<template v-slot:top>
<v-toolbar flat>
<v-toolbar-title>Device Table</v-toolbar-title>
<v-spacer></v-spacer>
<v-dialog v-model="dialog" max-width="500px">
<template v-slot:activator="{ props }">
<v-chip color="primary" pill class="ma-4" variant="outlined" v-bind="props" @click="dialog = true">Add New Exhibit</v-chip>
</template>
<v-card>
<v-card-title>
<span class="text-h5">{{ formTitle }}</span>
</v-card-title>
<v-card-text>
<v-form ref="form" v-model="valid">
<v-text-field v-model="editedItem.host" label="Host" :rules="[v => !!v || 'Host is required']">
</v-text-field>
<v-text-field v-model="editedItem.ip" label="IP"></v-text-field>
<v-text-field v-model="editedItem.mac" label="MAC"></v-text-field>
<!-- Add more form fields for other properties -->
</v-form>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn color="blue darken-1" text @click="close">Cancel</v-btn>
<v-btn color="blue darken-1" text @click="save" :disabled="!valid">Save</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</v-toolbar>
</template>
<template v-slot:item="{ item }">
<tr @click="toggleExpansion(item)">
<td v-for="header in visibleHeaders" :key="header.key">
{{ item[header.key] }}
</td>
<td>
<v-tooltip bottom>
<template v-slot:activator="{ props }">
<v-icon small class="mr-2" v-bind="props" @click.stop="editItem(item)">mdi-pencil</v-icon>
</template>
<span>Edit Host</span>
</v-tooltip>
<v-tooltip bottom>
<template v-slot:activator="{ props }">
<v-icon small v-bind="props" @click.stop="deleteItem(item)">mdi-delete</v-icon>
</template>
<span>Delete Host</span>
</v-tooltip>
</td>
</tr>
</template>
<template v-slot:expanded-row="{ columns, item }">
<tr>
<td :colspan="columns.length">
<div class="expanded-row-card">
<v-card>
<v-card-text>
<v-row>
<v-col v-for="header in headers" :key="header.key" cols="12" sm="6" md="4">
<strong>{{ header.title }}:</strong> {{ item[header.key] }}
</v-col>
</v-row>
</v-card-text>
</v-card>
</div>
</td>
</tr>
</template>
</v-data-table>
</template>
<script>
export default {
data() {
return {
headers: [
{ title: 'Host', key: 'host' },
{ title: 'IP', key: 'ip' },
{ title: 'MAC', key: 'mac' },
{ title: 'RackLocation', key: 'RackLocation' },
{ title: 'CrestronID', key: 'CrestronID' },
{ title: 'Manufacturer', key: 'Manufacturer' },
{ title: 'Model', key: 'Model' },
{ title: 'SerialTag', key: 'SerialTag' },
{ title: 'Display', key: 'Display' },
{ title: 'Speakers', key: 'Speakers' },
{ title: 'USB2', key: 'USB2' },
{ title: 'USB3', key: 'USB3' },
{ title: 'PowerMonitoring', key: 'PowerMonitoring' },
{ title: 'Notes', key: 'Notes' },
{ title: 'Actions', key: 'actions', sortable: false },
],
items: [
{
"host": "TIMELINE1",
"ip": "10.4.101.133",
"mac": "A4:BB:6D:86:40:A7",
"Static": "Yes",
"Active": "Yes",
"RackLocation": "5.4",
"CrestronID": "1",
"Manufacturer": "Dell",
"Model": "Precision 3240",
"SerialTag": "JZDDVD3",
"Display": "Ideum Presenter 43",
"Speakers": "Brown Innovations 24",
"USB2": "Touch, Amp",
"USB3": "",
"PowerMonitoring": "Netio PowerCable REST 101s",
"Notes": ""
},
{
"host": "TIMELINE2",
"ip": "10.4.101.14",
"mac": "A4:BB:6D:88:04:FA",
"Static": "Yes",
"Active": "Yes",
"RackLocation": "5.4",
"CrestronID": "1",
"Manufacturer": "Dell",
"Model": "Precision 3240",
"SerialTag": "JZDDVD3",
"Display": "Ideum Presenter 43",
"Speakers": "Brown Innovations 24",
"USB2": "Touch, Amp",
"USB3": "",
"PowerMonitoring": "Netio PowerCable REST 101s",
"Notes": ""
},
{
"host": "SIDD1",
"ip": "10.4.101.197",
"mac": "A4:BB:6D:88:06:3C"
},
{
"host": "SIDD2",
"ip": "10.4.101.175",
"mac": "A4:BB:6D:88:06:07"
},
{
"host": "SIDD3",
"ip": "10.4.101.215",
"mac": "A4:BB:6D:AB:1C:DC"
},
],
itemsPerPage: 10,
expanded: [],
visibleHeaders: [],
breakpoints: {
sm: 600,
md: 960,
lg: 1300,
},
dialog: false,
editedIndex: -1,
editedItem: {
host: '',
ip: '',
mac: '',
// Add more properties as needed
},
defaultItem: {
host: '',
ip: '',
mac: '',
// Add more properties as needed
},
valid: true,
};
},
computed: {
formTitle() {
return this.editedIndex === -1 ? 'New Item' : 'Edit Item';
},
},
methods: {
updateVisibleHeaders() {
const screenWidth = window.innerWidth;
if (screenWidth >= this.breakpoints.lg) {
this.visibleHeaders = this.headers.filter(
(header) =>
header.key === 'host' ||
header.key === 'ip' ||
header.key === 'mac' ||
header.key === 'RackLocation' ||
header.key === 'CrestronID' ||
header.key === 'actions'
);
} else if (screenWidth >= this.breakpoints.md) {
this.visibleHeaders = this.headers.filter(
(header) =>
header.key === 'host' ||
header.key === 'ip' ||
header.key === 'mac' ||
header.key === 'RackLocation' ||
header.key === 'actions'
);
} else if (screenWidth >= this.breakpoints.sm) {
this.visibleHeaders = this.headers.filter(
(header) =>
header.key === 'host' ||
header.key === 'ip' ||
header.key === 'mac'
);
} else {
this.visibleHeaders = this.headers.filter(
(header) => header.key === 'host' || header.key === 'ip'
);
}
},
toggleExpansion(item) {
const index = this.expanded.indexOf(item.id);
if (index > -1) {
this.expanded.splice(index, 1);
} else {
this.expanded = [item.id];
}
},
editItem(item) {
this.editedIndex = this.items.indexOf(item);
this.editedItem = Object.assign({}, item);
this.dialog = true;
},
deleteItem(item) {
const index = this.items.indexOf(item);
confirm('Are you sure you want to delete this item?') && this.items.splice(index, 1);
},
close() {
this.dialog = false;
this.$nextTick(() => {
this.editedItem = Object.assign({}, this.defaultItem);
this.editedIndex = -1;
});
},
save() {
if (this.$refs.form.validate()) {
if (this.editedIndex > -1) {
Object.assign(this.items[this.editedIndex], this.editedItem);
} else {
this.items.push(this.editedItem);
}
this.close();
}
},
},
watch: {
msg: {
handler(newValue) {
if (newValue && newValue.payload) {
this.items = newValue.payload.map((item, index) => ({
...item,
id: index,
}));
}
},
deep: true,
immediate: true,
},
},
mounted() {
this.updateVisibleHeaders();
window.addEventListener('resize', this.updateVisibleHeaders);
},
beforeUnmount() {
window.removeEventListener('resize', this.updateVisibleHeaders);
},
};
</script>
<style scoped>
.expanded-row-card {
margin-top: 8px;
margin-bottom: 8px;
}
</style>