I have a Vuetify v-data-table-server
(docs) which updates itself by fetching data from API.
<template>
<v-data-table-server
v-if="events.length > 0"
v-model:items-per-page="events_limit"
:headers="headers"
:items-length="events_total"
:items="events"
:loading="loading"
item-key="e_id"
@update:options="loadItems">
<template #item.e_created_at="{ item }">
<event-date :initialDate="item.raw.e_created_at" />
{{ item.raw.e_created_at }}
</template>
<template #item.e_status="{ item }">
{{ item.raw.e_status }}
</template>
</v-data-table-server>
</template>
<script>
import userService from "user.service";
import EventDate from "EventDate.vue";
export default {
name: "Events",
props: ["page"],
computed: {},
components: {
EventDate,
},
data: () => ({
isLoading: false,
isSuccess: false,
events: [],
events_offset: 0,
events_limit: 10,
loading: true,
headers: [
{
title: "Date",
align: "start",
sortable: true,
key: "e_created_at",
},
{
title: "Result",
align: "start",
sortable: true,
key: "e_status",
},
],
}),
mounted() {
this.loadItems({ page: 1, itemsPerPage: 10 });
},
methods: {
loadItems({ page, itemsPerPage, sortBy }) {
this.loading = true;
userService
.get_events({
limit: itemsPerPage,
offset: (page - 1) * itemsPerPage,
sort_by: sortBy,
})
.then(
(response) => {
this.events_total = response.events_total;
this.events = response.events;
this.loading = false;
},
(error) => {
console.log(error);
}
)
},
},
};
</script>
I also have an EventDate
component which is simply formatting the date:
<template>
<div>
<span>{{ formattedDate }}</span>
</div>
</template>
<script>
export default {
name: "EventDate",
props: {
initialDate: {
type: String,
required: true,
},
},
data() {
return {
date: "",
};
},
computed: {
formattedDate() {
const dt = new Date(this.date);
const day = dt.getDate().toString().padStart(2, "0");
const month = (dt.getMonth() + 1).toString().padStart(2, "0");
const year = dt.getFullYear();
const hours = dt.getHours().toString().padStart(2, "0");
const minutes = dt.getMinutes().toString().padStart(2, "0");
const seconds = dt.getSeconds().toString().padStart(2, "0");
return `${day}.${month}.${year} ${hours}:${minutes}:${seconds}`;
},
},
created() {
this.date = this.initialDate; // Set the initial date when component is created
},
};
</script>
When the first page is fetched, everything seems normal: components are showing formatted data.
But when I jump to another page, though I get correct values from API and I even see them in the table, EventDate
component instances are not updated:
What am I missing?
OK, ChatGPT got it right.
When the table updates its data from the API, Vue tries to be as efficient as possible in re-rendering the components. In some cases, components with similar properties are re-used rather than destroyed and recreated. As a result, the created() lifecycle hook might not be called again when you change the page.
I added this to my EventDate.vue
:
export default {
...,
watch: {
initialDate(newVal) {
this.date = newVal;
},
},
...
}
And now both parts of the cell are updated when I navigate through table pages.