JavaScript how do i iterate over every current and future element in a HTMLcollection?

432 views Asked by At

An HTMLCollection in the HTML DOM is live; it is automatically updated when the underlying document is changed.

im trying to write a simple script, for a website that often adds elements, that recolors those elements based on criteria.

now, i dont want to have a loop continusly running and checking for new elements, for performance reasons.

how would i use a live HTMLcollectio nand execute a function on every element in it, even the new ones added?

if i can accomplish this, it should result in a script that never finishes, and recolors all new elements.

any help appreciated!

1

There are 1 answers

0
Get Off My Lawn On

I would use a MutationObserver to accomplish this task. It will watch a node for changes, and if needed it will watch the subtree for changes as well (which I don't think is needed here). As nodes get added, we can send the node to a function to apply some feature on it. In the example below we just randomly select a color and set the background.

let targetNode = document.getElementById('watch')

// Apply feature on the node
function colorNode(node) {
  let r = Math.floor(Math.random() * 255)
  let g = Math.floor(Math.random() * 255)
  let b = Math.floor(Math.random() * 255)
  node.style.background = `rgb(${r},${g},${b})`
}

// Watch the node for changes (you can watch the subTree if needed)
let observerOptions = {
  childList: true
}

// Create the callback for when the mutation gets triggered
let observer = new MutationObserver(mutationList => {
  // Loop over the mutations
  mutationList.forEach(mutation => {
    // For added nodes apply the color function
    mutation.addedNodes.forEach(node => {
      colorNode(node)
    })
  })
})

// Start watching the target with the configuration
observer.observe(targetNode, observerOptions)

/////////////////
/// Testing
/////////////////
// Apply the inital color
Array.from(targetNode.children).forEach(child => colorNode(child))

// Create nodes on an interval for testing
setInterval(() => {
  let newNode = document.createElement('div')
  // Some random text
  newNode.textContent = (Math.random() * 1000).toString(32)
  targetNode.appendChild(newNode)
}, 2000)
<div id="watch">
  <div>One</div>
  <div>Two</div>
  <div>Three</div>
</div>