diff --git a/app/Views/shared/script_requests.php b/app/Views/shared/script_requests.php index d0bffb6..4ffab28 100644 --- a/app/Views/shared/script_requests.php +++ b/app/Views/shared/script_requests.php @@ -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 = '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; }, /* diff --git a/app/Views/shared/script_validation.php b/app/Views/shared/script_validation.php index a05bc07..b0af50f 100644 --- a/app/Views/shared/script_validation.php +++ b/app/Views/shared/script_validation.php @@ -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();