Replies: 3 comments 3 replies
-
Hey, elements that htmx itself removes are automatically cleaned up. |
Beta Was this translation helpful? Give feedback.
-
I have the same question. I need to attach scripts to some components. Some of these scripts require the proper dismount to stop timers, cancel fetches, release observers etc. Potentially it may be even small react/vue-powered 'islands'. Now I'm using the simple automount function (some housekeeping/checks omitted for clarity): function AutoMounter() {
const repo = new Map();
function mount(selector, func) {
repo.set(selector, func);
}
function install_handler(elt, f) {
const cleanup = f(elt);
if (cleanup) {
htmx.on(elt, 'htmx:beforeCleanupElement', (evt) => {
if (evt.detail.elt === elt)
cleanup();
});
}
}
function onload(content) {
repo.forEach((f, selector) => {
if (content.matches(selector))
install_handler(content, f);
content.querySelectorAll(selector).forEach((elt) => install_handler(elt, f));
});
}
htmx.onLoad(onload);
return { mount };
} Scripts mounts as soon as htmx loads elements with matching selectors. Example of usage with the bootstrap modal - open modal on mount, dispose on dismount. automounter = AutoMounter()
automounter.mount('.modal', (elt) => {
const modal = bootstrap.Modal.getOrCreateInstance(elt);
modal.show();
return () => { modal.hide(); modal.dispose(); }
}) The question is it the right way to do cleanup ? |
Beta Was this translation helpful? Give feedback.
-
@Telroshan, thank you for the MutationObserver suggestion. I'm not into the frontend that much, so I didn't knew such thing exists. In case some would find it useful, I ended up with this MutationObserver-powered automounter: class AutoMounter {
constructor() {
this.is_started = false;
this.handlers = new Map();
this.active_elts = new Map();
this.observer = new MutationObserver(this._observe.bind(this));
}
_process_removed(nodes) {
for (const node of nodes) {
for (const [elt, cleanup] of this.active_elts.entries()) {
if (node.contains(elt)) {
this.active_elts.delete(elt);
if (cleanup) {
cleanup();
}
}
}
}
}
_install_handler(elt, handler) {
if (!elt.isConnected) return;
if (this.active_elts.has(elt)) return;
const cleanup = handler(elt);
this.active_elts.set(elt, cleanup);
}
_process_added(nodes) {
for (const node of nodes) {
for (const [selector, handler] of this.handlers) {
if (node.matches(selector)) {
this._install_handler(node, handler);
}
for (const sub of node.querySelectorAll(selector)) {
this._install_handler(sub, handler);
}
}
}
}
_take_elements(nodelist) {
return Array.from(nodelist).filter((node) => node.nodeType === Node.ELEMENT_NODE);
}
_observe(records) {
for (const record of records) {
this._process_removed(this._take_elements(record.removedNodes));
this._process_added(this._take_elements(record.addedNodes));
}
}
start() {
this.is_started = true;
this._process_added(this._take_elements(document.body.childNodes));
this.observer.observe(document.body, { childList: true, subtree: true });
}
register(selector, handler) {
if (this.handlers.has(selector)) {
throw 'Selector already registered';
}
this.handlers.set(selector, handler);
if (this.is_started) {
this._process_added(this._take_elements(document.body.childNodes));
}
}
unregister(selector) {
if (!this.handlers.has(selector)) return;
if (this.is_started) {
this._process_removed(this._take_elements(document.body.querySelectorAll(selector)));
}
this.handlers.delete(selector);
}
} Usage const automounter = new AutoMounter();
automounter.register('.modal', (elt) => { /* modal code here */});
automounter.register('.chart', (elt) => { /* chart code here */});
...
automounter.start() |
Beta Was this translation helpful? Give feedback.
-
Hi all, I have htmx components with inner script to listen some event in the component. But every i made change between components (ie. component A replaced with component B), the event listener in previous component still active. Currently i use htmx:beforeRequest to cleanup the event, but i curious if in here have another way to cleanup event/subscription. Thanks.
Beta Was this translation helpful? Give feedback.
All reactions