Vandervals Vandervals - 3 months ago 13
Javascript Question

Is it possible to make querySelectorAll live like getElementsByTagName?

getElementsByTagName()
has 2 great features: it is fast and it is live. But what if I want to get
p strong
. Of course I could refine a selection using
getElementsByTagName()
again but wouldn't I lose the live effect for the new
p
tags?

Is there a way to turn
querySelectorAll
into a live selector?

Or... is there a way to use
getElementsByTagName()
and
getElementsByClassName()
to create a function that works in a similar way (at least with descendants) as
querySelectorAll
but being live?

Answer

Consider using mutation observers. Watch for childList with subtree: true. When the notification arrives, you can examine each added node with matches to see if it matches some selector.

function querySelectorAllLive(element, selector) {

  // Initialize results with current nodes.
  var result = Array.prototype.slice.call(element.querySelectorAll(selector));

  // Create observer instance.
  var observer = new MutationObserver(function(mutations) {
    mutations.forEach(function(mutation) {
      [].forEach.call(mutation.addedNodes, function(node) {
        if (node.nodeType === Node.ELEMENT_NODE && node.matches(selector)) {
          result.push(node);
        }
      });
    });
  });

  // Set up observer.
  observer.observe(element, { childList: true, subtree: true });

  return result;
}