Earlgray
Earlgray

Reputation: 647

How to automatically map a function to a newly added DOM element

I'm trying to automate calling a function (initBox) on all elements with class box on the page in vanilla javascript. I have made a functional solution except that it only applies to elements that are on the page when it is loaded. If I add an element to the DOM using javascript, the function (initBox) is not called on it.

Of course I can call the function (initBox) manually after adding the element, but I would like to automate it.

I'm looking for something similar to what jQuery does for events.

For example:

$('table').on('click', 'td', function (event) {
    doSomething();
});

This event is called even if I add the TD element to the table later via javascript.

Here is my current solution:

function addBox() {
  var btn = document.getElementsByTagName('button')[0];
  
  var el = document.createElement('div');
  el.classList.add('box');
  el.innerText = (document.getElementsByTagName('div').length + 1);
  
  btn.before(el);
}

function initBox(el) {
  el.innerText += ' Initialized';
}

document.querySelectorAll('.box').forEach(initBox);
.box {
  display: inline-block;
  border: 1px solid #1f2227;
  padding: 20px;
}

button {
  padding: 20px;
}
<div class="box">1</div>
<div class="box">2</div>

<button onclick="addBox()">Add box</button>

Upvotes: 0

Views: 226

Answers (2)

Peter Seliger
Peter Seliger

Reputation: 13432

The OP's problem can be solved just by the usage of a MutationObserver instance where the OP needs the callback from the list off added nodes just to initialize the very nodes which do match the OP's definition of a box.

function addBox() {
  var btn = document.getElementsByTagName('button')[0];
  
  var el = document.createElement('div');
  el.classList.add('box');
  el.innerText = (document.getElementsByTagName('div').length + 1);
  
  btn.before(el);
}


function initBox(el) {
  el.innerText += ' Initialized';
}
document.querySelectorAll('.box').forEach(initBox);


function initializeBoxClassDivOnly(node) {
  if (node.nodeType === 1 && node.matches('div.box')) {

    initBox(node);
  }
}
function handleNodeInsertion(mutationList/*, observer*/) {
  for (const mutation of mutationList) {
    mutation
      .addedNodes
      .forEach(initializeBoxClassDivOnly);
  }
};
const observer = new MutationObserver(handleNodeInsertion);
observer
  .observe(document.body, { childList: true, subtree: true });
.box {
  display: inline-block;
  border: 1px solid #1f2227;
  padding: 20px;
}
button {
  padding: 20px;
}
<div class="box">1</div>
<div class="box">2</div>

<button onclick="addBox()">Add box</button>

Upvotes: 1

Mubarak Salley
Mubarak Salley

Reputation: 35

Look Into Mutation Observers, they are the new way of observing dom objects, it allows you to run a function when an item is added or removed or modified in a particular DOM element, or if you want you can go old school ( meaning you add event listeners).

Mutation Observers ( Recommended Method ) https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver

Old School Evens https://developer.mozilla.org/en-US/docs/Web/API/MutationEvent

if you want me to write the code, let me know in the comments.

Upvotes: 0

Related Questions