Refactor Alpine.js components: remove memory cleanup code from requests, fix keyboard event handling in validation

This commit is contained in:
mahdahar 2026-02-16 10:23:23 +07:00
parent 79e6ab63a0
commit e947fc74d4
2 changed files with 18 additions and 40 deletions

View File

@ -112,9 +112,6 @@ document.addEventListener('alpine:init', () => {
this.totalPages = Math.ceil(this.filtered.length / this.pageSize) || 1; this.totalPages = Math.ceil(this.filtered.length / this.pageSize) || 1;
}, },
// Track timeouts for cleanup
toastTimeouts: [],
init() { init() {
this.today = new Date().toISOString().slice(0, 10); this.today = new Date().toISOString().slice(0, 10);
this.filter.date1 = this.today; this.filter.date1 = this.today;
@ -123,58 +120,36 @@ 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';
// Single consolidated watcher for list changes // Watchers for reactive updates
this.$watch('list', () => { this.$watch('list', () => {
this.computeFiltered(); this.computeFiltered();
this.computeValidatedCount(); this.computeValidatedCount();
}); });
// Single watcher for filter changes
this.$watch('filterKey', () => this.computeFiltered()); this.$watch('filterKey', () => this.computeFiltered());
this.$watch('filterTable', () => { this.$watch('filterTable', () => {
this.currentPage = 1; this.currentPage = 1;
this.computeFiltered(); this.computeFiltered();
}); });
// Single watcher for computed chain
this.$watch('filtered', () => { this.$watch('filtered', () => {
this.computeSorted(); this.computeSorted();
this.computeTotalPages(); this.computeTotalPages();
}); });
// Sort changes trigger pagination update
this.$watch('sortCol', () => this.computeSorted()); this.$watch('sortCol', () => this.computeSorted());
this.$watch('sortAsc', () => this.computeSorted()); this.$watch('sortAsc', () => this.computeSorted());
this.$watch('sorted', () => this.computePaginated()); this.$watch('sorted', () => this.computePaginated());
this.$watch('currentPage', () => this.computePaginated()); this.$watch('currentPage', () => this.computePaginated());
// Watch audit data changes to recompute events
this.$watch('auditData', () => { this.$watch('auditData', () => {
this.computeAuditEvents(); this.computeAuditEvents();
}); });
// Register cleanup on destroy // Initial load only - no auto-refresh
this.$cleanup(() => this.destroy());
this.fetchList(); this.fetchList();
}, },
// Cleanup method to prevent memory leaks
destroy() {
// Clear all tracked timeouts
this.toastTimeouts.forEach(id => clearTimeout(id));
this.toastTimeouts = [];
// Clear large data structures
this.list = [];
this.filtered = [];
this.sorted = [];
this.paginated = [];
this.auditData = null;
this.item = null;
this.previewItem = null;
},
fetchList() { fetchList() {
this.isLoading = true; this.isLoading = true;
this.list = []; this.list = [];
@ -557,13 +532,7 @@ document.addEventListener('alpine:init', () => {
toast.className = `alert alert-${type} fixed top-4 right-4 z-50`; toast.className = `alert alert-${type} fixed top-4 right-4 z-50`;
toast.innerHTML = `<i class="fa ${type === 'error' ? 'fa-times-circle' : 'fa-check-circle'}"></i> ${message}`; toast.innerHTML = `<i class="fa ${type === 'error' ? 'fa-times-circle' : 'fa-check-circle'}"></i> ${message}`;
document.body.appendChild(toast); document.body.appendChild(toast);
const timeoutId = setTimeout(() => { setTimeout(() => toast.remove(), 2000);
toast.remove();
// Remove from tracking array
const idx = this.toastTimeouts.indexOf(timeoutId);
if (idx > -1) this.toastTimeouts.splice(idx, 1);
}, 2000);
this.toastTimeouts.push(timeoutId);
}, },
})); }));
}); });

View File

@ -86,7 +86,7 @@ document.addEventListener('alpine:init', () => {
this.currentPage = 1; this.currentPage = 1;
}); });
// Set up watchers to update cached computed properties // Watchers for reactive updates
this.$watch('unvalidatedList', () => { this.$watch('unvalidatedList', () => {
this.computeUnvalidatedFiltered(); this.computeUnvalidatedFiltered();
this.computeUnvalidatedCount(); this.computeUnvalidatedCount();
@ -111,13 +111,12 @@ document.addEventListener('alpine:init', () => {
this.computeUnvalidatedPaginated(); this.computeUnvalidatedPaginated();
}); });
// Auto-fetch on page load // Initial load only - no auto-refresh
this.fetchUnvalidated(); this.fetchUnvalidated();
// Keyboard shortcuts for dialog // Keyboard shortcuts - added/removed when dialog opens/closes
document.addEventListener('keydown', (e) => { this._keyboardHandler = (e) => {
if (this.isDialogValOpen) { if (this.isDialogValOpen) {
// N key - skip to next
if (e.key === 'n' || e.key === 'N') { if (e.key === 'n' || e.key === 'N') {
if (!e.target.closest('input, textarea, button')) { if (!e.target.closest('input, textarea, button')) {
e.preventDefault(); e.preventDefault();
@ -125,7 +124,8 @@ document.addEventListener('alpine:init', () => {
} }
} }
} }
}); };
document.addEventListener('keydown', this._keyboardHandler);
}, },
fetchUnvalidated() { fetchUnvalidated() {
@ -198,6 +198,10 @@ document.addEventListener('alpine:init', () => {
this.valAccessnumber = item.SP_ACCESSNUMBER; this.valAccessnumber = item.SP_ACCESSNUMBER;
this.valItem = item; this.valItem = item;
this.isDialogValOpen = true; this.isDialogValOpen = true;
// Re-add keyboard handler when dialog opens
if (this._keyboardHandler) {
document.addEventListener('keydown', this._keyboardHandler);
}
setTimeout(() => { setTimeout(() => {
const btn = document.getElementById('validate-btn'); const btn = document.getElementById('validate-btn');
if (btn) btn.focus(); if (btn) btn.focus();
@ -225,6 +229,11 @@ document.addEventListener('alpine:init', () => {
} }
this.validationDelayRemaining = 0; this.validationDelayRemaining = 0;
this.isIframeLoaded = false; this.isIframeLoaded = false;
// Remove keyboard handler when dialog closes
if (this._keyboardHandler) {
document.removeEventListener('keydown', this._keyboardHandler);
this._keyboardHandler = null;
}
}, },
skipToNext() { skipToNext() {