From 69abf8d49a5d3daae11096a7f5c84bd7c445e267 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Fromme?= Date: Tue, 11 Feb 2025 08:16:30 +0100 Subject: [PATCH] feat: properly destroy objects on disconnect from dom --- assets/controllers/autocomplete_controller.js | 7 ++++++- assets/controllers/sortable_controller.js | 6 +++++- assets/controllers/tooltip_controller.js | 6 +++++- .../controllers/upload_collection_controller.js | 16 ++++++++++------ 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/assets/controllers/autocomplete_controller.js b/assets/controllers/autocomplete_controller.js index c4d48f7..d75d401 100644 --- a/assets/controllers/autocomplete_controller.js +++ b/assets/controllers/autocomplete_controller.js @@ -46,7 +46,7 @@ export default class extends Controller { })) } - new Autocomplete(this.element, { + this.autocomplete = new Autocomplete(this.element, { search: searchHandler, getResultValue: result => result.text, submitOnEnter: true, @@ -58,6 +58,7 @@ export default class extends Controller { this.selectedValue = true } + // prevent form submission when selecting entry in autocomplete list with enter key this.element.addEventListener('keypress', e => { if (e.key === 'Enter') { e.preventDefault() @@ -76,4 +77,8 @@ export default class extends Controller { this.resetButtonTarget.classList.toggle('hidden', false === this.selectedValue) this.searchIconTarget.classList.toggle('hidden', this.selectedValue) } + + disconnect() { + this.autocomplete.destroy() + } } diff --git a/assets/controllers/sortable_controller.js b/assets/controllers/sortable_controller.js index 958f826..660e70d 100644 --- a/assets/controllers/sortable_controller.js +++ b/assets/controllers/sortable_controller.js @@ -7,7 +7,7 @@ export default class extends Controller { static targets = ['item', 'handle'] connect() { - new Sortable(this.element, { + this.sortable = new Sortable(this.element, { item: '[data-sortable-target="item"]', handle: '[data-sortable-target="handle"]', onEnd: e => { @@ -31,4 +31,8 @@ export default class extends Controller { body: JSON.stringify({ ordering: ordering }) }) } + + disconnect() { + this.sortable.destroy() + } } diff --git a/assets/controllers/tooltip_controller.js b/assets/controllers/tooltip_controller.js index a95ecd7..b7d9139 100644 --- a/assets/controllers/tooltip_controller.js +++ b/assets/controllers/tooltip_controller.js @@ -31,6 +31,10 @@ export default class extends Controller { } else { element = this.element } - tippy(element, options) + this.tooltip = tippy(element, options) + } + + disconnect() { + this.tooltip.destroy() } } diff --git a/assets/controllers/upload_collection_controller.js b/assets/controllers/upload_collection_controller.js index ddc0811..3898a70 100644 --- a/assets/controllers/upload_collection_controller.js +++ b/assets/controllers/upload_collection_controller.js @@ -22,7 +22,7 @@ export default class extends Controller { connect () { useFetch(this) - const dropzone = new Dropzone(this.dropzoneTarget, { + this.dropzone = new Dropzone(this.dropzoneTarget, { url: this.endpointUploadValue, withCredentials: true, maxFiles: this.maxFilesValue, @@ -42,15 +42,15 @@ export default class extends Controller { dictMaxFilesExceeded: this.languageValue.maxFilesExceeded, }) - dropzone.on('addedfile', file => { + this.dropzone.on('addedfile', file => { this.errorsTarget.classList.add('hidden') }) - dropzone.on('removedfile', (file) => { + this.dropzone.on('removedfile', (file) => { fetch(`${this.endpointDeleteValue}?uuid=${file.upload.uuid}`, { method: 'delete', credentials: 'include' }) }) - dropzone.on('sending', (file, xhr, formData) => { + this.dropzone.on('sending', (file, xhr, formData) => { if (this.hasParamsValue) { let keys = Object.keys(this.paramsValue) keys.forEach(key => { @@ -62,14 +62,18 @@ export default class extends Controller { window.dispatchEvent(new CustomEvent('dropzone:uploading')) }) - dropzone.on('queuecomplete', () => { + this.dropzone.on('queuecomplete', () => { window.dispatchEvent(new CustomEvent('dropzone:complete')) }) - dropzone.on('error', (file, errorMessage) => { + this.dropzone.on('error', (file, errorMessage) => { this.errorsTarget.innerText = errorMessage this.errorsTarget.classList.remove('hidden') dropzone.removeFile(file) }) } + + disconnect() { + this.dropzone.destroy() + } }