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,
|
||||
pageSize: 30,
|
||||
|
||||
// Cached computed properties to prevent memory leak
|
||||
filtered: [],
|
||||
sorted: [],
|
||||
paginated: [],
|
||||
totalPages: 1,
|
||||
validatedCount: 0,
|
||||
|
||||
sort(col) {
|
||||
if (this.sortCol === col) {
|
||||
this.sortAsc = !this.sortAsc;
|
||||
@ -64,12 +71,30 @@ document.addEventListener('alpine:init', () => {
|
||||
if (this.currentPage > 1) this.currentPage--;
|
||||
},
|
||||
|
||||
get totalPages() {
|
||||
return Math.ceil(this.filtered.length / this.pageSize) || 1;
|
||||
// Compute methods - called only when dependencies change
|
||||
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() {
|
||||
return this.filtered.slice().sort((a, b) => {
|
||||
computeSorted() {
|
||||
this.sorted = this.filtered.slice().sort((a, b) => {
|
||||
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;
|
||||
@ -77,10 +102,14 @@ document.addEventListener('alpine:init', () => {
|
||||
});
|
||||
},
|
||||
|
||||
get paginated() {
|
||||
computePaginated() {
|
||||
const start = (this.currentPage - 1) * 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() {
|
||||
@ -97,6 +126,34 @@ document.addEventListener('alpine:init', () => {
|
||||
const defaultPrinter = '<?= $config[session()->get("userrole")]["sampleDialog"]["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();
|
||||
},
|
||||
|
||||
@ -139,28 +196,9 @@ document.addEventListener('alpine:init', () => {
|
||||
isValidated(item) {
|
||||
return item.ISVAL == 1 && item.ISPENDING != 1;
|
||||
},
|
||||
get filtered() {
|
||||
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)
|
||||
)
|
||||
);
|
||||
}
|
||||
return filteredList;
|
||||
},
|
||||
get validatedCount() {
|
||||
return this.list.filter(r => this.isValidated(r)).length;
|
||||
|
||||
computeValidatedCount() {
|
||||
this.validatedCount = this.list.filter(r => this.isValidated(r)).length;
|
||||
},
|
||||
|
||||
/*
|
||||
|
||||
@ -15,6 +15,13 @@ document.addEventListener('alpine:init', () => {
|
||||
currentPage: 1,
|
||||
pageSize: 30,
|
||||
|
||||
// Cached computed properties to prevent memory leak
|
||||
unvalidatedFiltered: [],
|
||||
unvalidatedSorted: [],
|
||||
unvalidatedPaginated: [],
|
||||
unvalidatedTotalPages: 1,
|
||||
unvalidatedCount: 0,
|
||||
|
||||
sort(col) {
|
||||
if (this.sortCol === col) {
|
||||
this.sortAsc = !this.sortAsc;
|
||||
@ -32,12 +39,22 @@ document.addEventListener('alpine:init', () => {
|
||||
if (this.currentPage > 1) this.currentPage--;
|
||||
},
|
||||
|
||||
get unvalidatedTotalPages() {
|
||||
return Math.ceil(this.unvalidatedFiltered.length / this.pageSize) || 1;
|
||||
// Compute methods - called only when dependencies change
|
||||
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() {
|
||||
return this.unvalidatedFiltered.slice().sort((a, b) => {
|
||||
computeUnvalidatedSorted() {
|
||||
this.unvalidatedSorted = this.unvalidatedFiltered.slice().sort((a, b) => {
|
||||
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;
|
||||
@ -45,24 +62,18 @@ document.addEventListener('alpine:init', () => {
|
||||
});
|
||||
},
|
||||
|
||||
get unvalidatedPaginated() {
|
||||
computeUnvalidatedPaginated() {
|
||||
const start = (this.currentPage - 1) * this.pageSize;
|
||||
const end = start + this.pageSize;
|
||||
return this.unvalidatedSorted.slice(start, end);
|
||||
this.unvalidatedPaginated = this.unvalidatedSorted.slice(start, end);
|
||||
},
|
||||
|
||||
get unvalidatedFiltered() {
|
||||
if (!this.filterTable) return this.unvalidatedList;
|
||||
const searchTerm = this.filterTable.toLowerCase();
|
||||
return this.unvalidatedList.filter(item =>
|
||||
Object.values(item).some(value =>
|
||||
String(value).toLowerCase().includes(searchTerm)
|
||||
)
|
||||
);
|
||||
computeUnvalidatedTotalPages() {
|
||||
this.unvalidatedTotalPages = Math.ceil(this.unvalidatedFiltered.length / this.pageSize) || 1;
|
||||
},
|
||||
|
||||
get unvalidatedCount() {
|
||||
return this.unvalidatedList.length;
|
||||
computeUnvalidatedCount() {
|
||||
this.unvalidatedCount = this.unvalidatedList.length;
|
||||
},
|
||||
|
||||
init() {
|
||||
@ -75,6 +86,31 @@ document.addEventListener('alpine:init', () => {
|
||||
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
|
||||
this.fetchUnvalidated();
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user