Reputation: 2311
I'm writing a web component enhancer function and I need to run something when the element is removed from the DOM - but I know this after the fact. I've used MutationObserver - but my component is used a lot around the page and multiple mutation observers are causing a performance issue.
Here's an attempt to do this without MutationObserver:
class TestComponent extends HTMLElement {
disconnectedCallback() {
console.log('CB');
}
}
window.customElements.define('test-component', TestComponent);
function enrichComponent(component) {
const originalDisconnectedCallback = component.disconnectedCallback;
component.disconnectedCallback = function() {
originalDisconnectedCallback();
console.log('CB1');
}
}
const component = document.createElement('test-component');
enhancer(component);
document.body.appendChild(component);
component.remove(); // logs 'CB' but no 'CB1'
This doesn't work.
Is there a way to 'monkeypatch' disconnectedCallback
?
Upvotes: 3
Views: 639
Reputation: 2311
I've managed to come up with a "hack" that is working and is less costly than mutation observers.
The idea is to create a component inside the enhancer function, append it to the web component and run the cleanup function from inside the mock component.
Here's an example:
class FormAssociationDisconnectionComponent extends HTMLElement {
disconnectedCallback() {
this.dispatchEvent(new Event('disconnected'));
}
}
window.customElements.define('form-association-disconnection', FormAssociationDisconnectionComponent);
function enrichComponent(component) {
// ... setup a form and a hidden input we need to cleanup
const removeListenerElement = document.createElement('form-association-disconnection');
removeListenerElement.addEventListener('disconnected', () => {
hiddenInput.remove();
hostingForm.removeEventListener('reset', resetFormHandler);
});
inputElement.appendChild(removeListenerElement);
}
This way, you can run any cleanup you want when your custom element is removed without creating multiple MutationObservers.
Upvotes: 0
Reputation: 1776
I'd break it into two solutions, each closer to the specific use-case:
hiddenElement
within that component - better to do the whole management within the component and not enrich/extend it from the outside (yes, even if you have this pattern repeated for a several components in the whole system)disconnectedCallback
should dispatch a disconnect
event and the listener should be attached to it - otherwise this solution is just not scaleable / open for extensions (think of the case when another teammate need to add some more logic on disconnect, logic that is decoupled from the one found in the first listener)Upvotes: 2