0

I'm thinking of introducing a new feature for BSN to support dynamic content, so I wrote something like this:

Sample code

// some context
const initCallback = (parent: ParentNode) => {
  // initialize all BSN components for the matched nodes in this parent
}
const removeDataAPI = (parent: ParentNode) => {
  // remove all BSN components for the matched nodes in this parent
}
const addListener = (target: EventTarget, eventName: string, listener: EventListener) => {
  return target.addEventListener(eventName, listener);
}

// overall callback
const loadCallback = (target?: ParentNode) => {
  // Select the node that will be observed for mutations
  const targetNode = target || document.body;
  // Initialize first
  initCallback(target);

  // Options for the observer (which mutations to observe)
  const config: MutationObserverInit = { childList: true, subtree: true };

  // Callback function to execute when mutations are observed
  const mutationCallback = (mutationList: MutationRecord[]) => {
    const filteredList = mutationList.filter(({ addedNodes, removedNodes }) =>
      [...addedNodes, ...removedNodes].every(
        n => isHTMLElement(n) && !matches(n, '.popover,.tooltip,.offcanvas-backdrop,.modal-backdrop'),
      ),
    );
    for (const mutation of filteredList) {
      if (mutation.type === 'childList') {
        // console.log('A child node has been added or removed.', mutation);
        [...mutation.addedNodes].forEach(n => initCallback(n as ParentNode));
        [...mutation.removedNodes].forEach(n => removeDataAPI(n as ParentNode));
      }
    }
  };

  // Create an observer instance linked to the callback function
  const observer = new MutationObserver(mutationCallback);

  // Start observing the target node for configured mutations
  observer.observe(targetNode, config);
};

// Bulk initialize all components
if (document.body) loadCallback(document.body);
else {
  addListener(document, 'DOMContentLoaded', () => loadCallback(), { once: true });
}

Questions

  • is this approach consistent for a framework agnostic design? (with other words: would this help for instance a React/Solid/Vue developer in any way?)
  • is this consistent in terms of performance? (should the observed be removed when user times out or tabs away the window and restart when user is back to page)
  • is this a better approach than the original Bootstrap jQuery like event delegation and component initialization on click (BSN attach event listeners directly to the targets only)?
  • is there anything this loadCallback could need improving?

Thank you!

thednp
  • 4,401
  • 4
  • 33
  • 45
  • 2
    1) Performance of this code depends on the complexity of DOM and frequency of updates, see [this answer](https://stackoverflow.com/a/39332340) that lists methods of improving MutationObserver performance. 2) addedNodes and removedNodes often contain DOM "trees" because modern frameworks try to render in detached state, so your `matches` won't catch a node inside. – wOxxOm Feb 18 '23 at 18:59
  • This is awesome tech however I don't see how to reinitialize `mutation.target`(s) for which other corresponding elements are contained within different `mutation.target`(s) and to filter out cases like popover/tooltip is quite the mess. Never the less, I thank you for your time to explain this stuff. – thednp Feb 19 '23 at 16:40

0 Answers0