Fix memory leak in Alpine.js computed properties
Replace getter-based computed properties with cached properties and explicit watchers to prevent memory leak in: - script_requests.php - script_validation.php
This commit is contained in:
parent
c1cf2bbc9f
commit
3577ee870f
@ -47,6 +47,13 @@ document.addEventListener('alpine:init', () => {
|
|||||||
currentPage: 1,
|
currentPage: 1,
|
||||||
pageSize: 30,
|
pageSize: 30,
|
||||||
|
|
||||||
|
// Cached computed properties to prevent memory leak
|
||||||
|
filtered: [],
|
||||||
|
sorted: [],
|
||||||
|
paginated: [],
|
||||||
|
totalPages: 1,
|
||||||
|
validatedCount: 0,
|
||||||
|
|
||||||
sort(col) {
|
sort(col) {
|
||||||
if (this.sortCol === col) {
|
if (this.sortCol === col) {
|
||||||
this.sortAsc = !this.sortAsc;
|
this.sortAsc = !this.sortAsc;
|
||||||
@ -64,12 +71,30 @@ document.addEventListener('alpine:init', () => {
|
|||||||
if (this.currentPage > 1) this.currentPage--;
|
if (this.currentPage > 1) this.currentPage--;
|
||||||
},
|
},
|
||||||
|
|
||||||
get totalPages() {
|
// Compute methods - called only when dependencies change
|
||||||
return Math.ceil(this.filtered.length / this.pageSize) || 1;
|
computeFiltered() {
|
||||||
|
let filteredList = this.list;
|
||||||
|
if (this.filterKey === 'Validated') {
|
||||||
|
filteredList = filteredList.filter(item => this.isValidated(item));
|
||||||
|
} else {
|
||||||
|
const validStatuses = this.statusMap[this.filterKey];
|
||||||
|
if (validStatuses.length > 0) {
|
||||||
|
filteredList = filteredList.filter(item => validStatuses.includes(item.STATS));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.filterTable) {
|
||||||
|
const searchTerm = this.filterTable.toLowerCase();
|
||||||
|
filteredList = filteredList.filter(item =>
|
||||||
|
Object.values(item).some(value =>
|
||||||
|
String(value).toLowerCase().includes(searchTerm)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.filtered = filteredList;
|
||||||
},
|
},
|
||||||
|
|
||||||
get sorted() {
|
computeSorted() {
|
||||||
return this.filtered.slice().sort((a, b) => {
|
this.sorted = this.filtered.slice().sort((a, b) => {
|
||||||
let modifier = this.sortAsc ? 1 : -1;
|
let modifier = this.sortAsc ? 1 : -1;
|
||||||
if (a[this.sortCol] < b[this.sortCol]) return -1 * modifier;
|
if (a[this.sortCol] < b[this.sortCol]) return -1 * modifier;
|
||||||
if (a[this.sortCol] > b[this.sortCol]) return 1 * modifier;
|
if (a[this.sortCol] > b[this.sortCol]) return 1 * modifier;
|
||||||
@ -77,10 +102,14 @@ document.addEventListener('alpine:init', () => {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
get paginated() {
|
computePaginated() {
|
||||||
const start = (this.currentPage - 1) * this.pageSize;
|
const start = (this.currentPage - 1) * this.pageSize;
|
||||||
const end = start + this.pageSize;
|
const end = start + this.pageSize;
|
||||||
return this.sorted.slice(start, end);
|
this.paginated = this.sorted.slice(start, end);
|
||||||
|
},
|
||||||
|
|
||||||
|
computeTotalPages() {
|
||||||
|
this.totalPages = Math.ceil(this.filtered.length / this.pageSize) || 1;
|
||||||
},
|
},
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
@ -97,6 +126,34 @@ document.addEventListener('alpine:init', () => {
|
|||||||
const defaultPrinter = '<?= $config[session()->get("userrole")]["sampleDialog"]["defaultPrinter"] ?? "lab" ?>';
|
const defaultPrinter = '<?= $config[session()->get("userrole")]["sampleDialog"]["defaultPrinter"] ?? "lab" ?>';
|
||||||
this.selectedPrinter = defaultPrinter || 'lab';
|
this.selectedPrinter = defaultPrinter || 'lab';
|
||||||
|
|
||||||
|
// Set up watchers to update cached computed properties
|
||||||
|
this.$watch('list', () => {
|
||||||
|
this.computeFiltered();
|
||||||
|
this.computeValidatedCount();
|
||||||
|
});
|
||||||
|
this.$watch('filterKey', () => {
|
||||||
|
this.computeFiltered();
|
||||||
|
});
|
||||||
|
this.$watch('filterTable', () => {
|
||||||
|
this.computeFiltered();
|
||||||
|
});
|
||||||
|
this.$watch('filtered', () => {
|
||||||
|
this.computeSorted();
|
||||||
|
this.computeTotalPages();
|
||||||
|
});
|
||||||
|
this.$watch('sortCol', () => {
|
||||||
|
this.computeSorted();
|
||||||
|
});
|
||||||
|
this.$watch('sortAsc', () => {
|
||||||
|
this.computeSorted();
|
||||||
|
});
|
||||||
|
this.$watch('sorted', () => {
|
||||||
|
this.computePaginated();
|
||||||
|
});
|
||||||
|
this.$watch('currentPage', () => {
|
||||||
|
this.computePaginated();
|
||||||
|
});
|
||||||
|
|
||||||
this.fetchList();
|
this.fetchList();
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -139,28 +196,9 @@ document.addEventListener('alpine:init', () => {
|
|||||||
isValidated(item) {
|
isValidated(item) {
|
||||||
return item.ISVAL == 1 && item.ISPENDING != 1;
|
return item.ISVAL == 1 && item.ISPENDING != 1;
|
||||||
},
|
},
|
||||||
get filtered() {
|
|
||||||
let filteredList = this.list;
|
computeValidatedCount() {
|
||||||
if (this.filterKey === 'Validated') {
|
this.validatedCount = this.list.filter(r => this.isValidated(r)).length;
|
||||||
filteredList = filteredList.filter(item => this.isValidated(item));
|
|
||||||
} else {
|
|
||||||
const validStatuses = this.statusMap[this.filterKey];
|
|
||||||
if (validStatuses.length > 0) {
|
|
||||||
filteredList = filteredList.filter(item => validStatuses.includes(item.STATS));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (this.filterTable) {
|
|
||||||
const searchTerm = this.filterTable.toLowerCase();
|
|
||||||
filteredList = filteredList.filter(item =>
|
|
||||||
Object.values(item).some(value =>
|
|
||||||
String(value).toLowerCase().includes(searchTerm)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return filteredList;
|
|
||||||
},
|
|
||||||
get validatedCount() {
|
|
||||||
return this.list.filter(r => this.isValidated(r)).length;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@ -15,6 +15,13 @@ document.addEventListener('alpine:init', () => {
|
|||||||
currentPage: 1,
|
currentPage: 1,
|
||||||
pageSize: 30,
|
pageSize: 30,
|
||||||
|
|
||||||
|
// Cached computed properties to prevent memory leak
|
||||||
|
unvalidatedFiltered: [],
|
||||||
|
unvalidatedSorted: [],
|
||||||
|
unvalidatedPaginated: [],
|
||||||
|
unvalidatedTotalPages: 1,
|
||||||
|
unvalidatedCount: 0,
|
||||||
|
|
||||||
sort(col) {
|
sort(col) {
|
||||||
if (this.sortCol === col) {
|
if (this.sortCol === col) {
|
||||||
this.sortAsc = !this.sortAsc;
|
this.sortAsc = !this.sortAsc;
|
||||||
@ -32,12 +39,22 @@ document.addEventListener('alpine:init', () => {
|
|||||||
if (this.currentPage > 1) this.currentPage--;
|
if (this.currentPage > 1) this.currentPage--;
|
||||||
},
|
},
|
||||||
|
|
||||||
get unvalidatedTotalPages() {
|
// Compute methods - called only when dependencies change
|
||||||
return Math.ceil(this.unvalidatedFiltered.length / this.pageSize) || 1;
|
computeUnvalidatedFiltered() {
|
||||||
|
if (!this.filterTable) {
|
||||||
|
this.unvalidatedFiltered = this.unvalidatedList;
|
||||||
|
} else {
|
||||||
|
const searchTerm = this.filterTable.toLowerCase();
|
||||||
|
this.unvalidatedFiltered = this.unvalidatedList.filter(item =>
|
||||||
|
Object.values(item).some(value =>
|
||||||
|
String(value).toLowerCase().includes(searchTerm)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
get unvalidatedSorted() {
|
computeUnvalidatedSorted() {
|
||||||
return this.unvalidatedFiltered.slice().sort((a, b) => {
|
this.unvalidatedSorted = this.unvalidatedFiltered.slice().sort((a, b) => {
|
||||||
let modifier = this.sortAsc ? 1 : -1;
|
let modifier = this.sortAsc ? 1 : -1;
|
||||||
if (a[this.sortCol] < b[this.sortCol]) return -1 * modifier;
|
if (a[this.sortCol] < b[this.sortCol]) return -1 * modifier;
|
||||||
if (a[this.sortCol] > b[this.sortCol]) return 1 * modifier;
|
if (a[this.sortCol] > b[this.sortCol]) return 1 * modifier;
|
||||||
@ -45,24 +62,18 @@ document.addEventListener('alpine:init', () => {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
get unvalidatedPaginated() {
|
computeUnvalidatedPaginated() {
|
||||||
const start = (this.currentPage - 1) * this.pageSize;
|
const start = (this.currentPage - 1) * this.pageSize;
|
||||||
const end = start + this.pageSize;
|
const end = start + this.pageSize;
|
||||||
return this.unvalidatedSorted.slice(start, end);
|
this.unvalidatedPaginated = this.unvalidatedSorted.slice(start, end);
|
||||||
},
|
},
|
||||||
|
|
||||||
get unvalidatedFiltered() {
|
computeUnvalidatedTotalPages() {
|
||||||
if (!this.filterTable) return this.unvalidatedList;
|
this.unvalidatedTotalPages = Math.ceil(this.unvalidatedFiltered.length / this.pageSize) || 1;
|
||||||
const searchTerm = this.filterTable.toLowerCase();
|
|
||||||
return this.unvalidatedList.filter(item =>
|
|
||||||
Object.values(item).some(value =>
|
|
||||||
String(value).toLowerCase().includes(searchTerm)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
get unvalidatedCount() {
|
computeUnvalidatedCount() {
|
||||||
return this.unvalidatedList.length;
|
this.unvalidatedCount = this.unvalidatedList.length;
|
||||||
},
|
},
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
@ -75,6 +86,31 @@ document.addEventListener('alpine:init', () => {
|
|||||||
this.currentPage = 1;
|
this.currentPage = 1;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Set up watchers to update cached computed properties
|
||||||
|
this.$watch('unvalidatedList', () => {
|
||||||
|
this.computeUnvalidatedFiltered();
|
||||||
|
this.computeUnvalidatedCount();
|
||||||
|
});
|
||||||
|
this.$watch('filterTable', () => {
|
||||||
|
this.computeUnvalidatedFiltered();
|
||||||
|
});
|
||||||
|
this.$watch('unvalidatedFiltered', () => {
|
||||||
|
this.computeUnvalidatedSorted();
|
||||||
|
this.computeUnvalidatedTotalPages();
|
||||||
|
});
|
||||||
|
this.$watch('sortCol', () => {
|
||||||
|
this.computeUnvalidatedSorted();
|
||||||
|
});
|
||||||
|
this.$watch('sortAsc', () => {
|
||||||
|
this.computeUnvalidatedSorted();
|
||||||
|
});
|
||||||
|
this.$watch('unvalidatedSorted', () => {
|
||||||
|
this.computeUnvalidatedPaginated();
|
||||||
|
});
|
||||||
|
this.$watch('currentPage', () => {
|
||||||
|
this.computeUnvalidatedPaginated();
|
||||||
|
});
|
||||||
|
|
||||||
// Auto-fetch on page load
|
// Auto-fetch on page load
|
||||||
this.fetchUnvalidated();
|
this.fetchUnvalidated();
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user