Home > Software design >  Add the same event listener to all buttons with for .. of loop
Add the same event listener to all buttons with for .. of loop

Time:10-28

I am having trouble with adding an event listener to each button of the document, using a for ... of loop.

var buttons = document.getElementsByTagName("button");

for (b of buttons) {
  b.addEventListener("click", function() {
    var n = document.createElement("span");
    n.innerHTML = "new";
    b.parentElement.appendChild(n);
    b.style.display = "none";
  });
}
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Test</title>
</head>
<body>
  <header>
    <h1>Heading</h1>
  </header>
  <main>
    <dl>
      <dt>Title</dt>
      <dd>Description</dd>
      <dt>Title</dt>
      <dd><button>add content</button></dd>
      <dt>Title</dt>
      <dd>Description</dd>
    </dl>
    <dl>
      <dt>Title</dt>
      <dd>Description</dd>
      <dt>Title</dt>
      <dd><button>add content</button></dd>
      <dt>Title</dt>
      <dd>Description</dd>
    </dl>
  </main>
</body>
</html>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

The above example only results in the appendig of n after the last button, not the first. Why is that and how can it be fixed? Is a for .. of loop even the right way to do this?

CodePudding user response:

The problem is that the 'for' in that way doesn't work. You should use it like this:

var buttons = document.getElementsByTagName("button");

for (var i = 0; i < buttons.length; i  ) {
  b[i].addEventListener("click", function() {
    var n = document.createElement("span");
    n.innerHTML = "new";
    b[i].parentElement.appendChild(n);
    b[i].style.display = "none";
  });
}

CodePudding user response:

From both of the above comments ...

"nitpicker mode ... does the OP mean the same or rather the selfsame or the very same. For the latter case(s) the OP then needs to provide the event listener as a single reference (maybe a function declaration) and not always another fully implemented anonymous callback function."

"In case the OP does utilize querySelectorAll the OP then can access a forEach which iterates over the returned NodeList ... document.querySelectorAll("button").forEach(/* ... */);"

And in addition to the already said, the OP might retrieve the currently click button as currentTarget of the provided event object.

function handleContentCreation(evt) {
  const button = evt.currentTarget;

  const content = document.createElement('span');
  content.textContent = 'new';

  button.parentElement.appendChild(content);
  button.style.display = 'none';
}

document
  .querySelectorAll('button')
  .forEach(elmNode =>
    elmNode.addEventListener('click', handleContentCreation)
  );
:not(dd) { margin: 0!important; padding: 0!important }
body { zoom: .9; }
h1 { font-size: 1.2em; }
<header>
  <h1>Heading</h1>
</header>
<main>
  <dl>
    <dt>Title</dt>
    <dd>Description</dd>
    <dt>Title</dt>
    <dd><button>add content</button></dd>
    <dt>Title</dt>
    <dd>Description</dd>
  </dl>
  <dl>
    <dt>Title</dt>
    <dd>Description</dd>
    <dt>Title</dt>
    <dd><button>add content</button></dd>
    <dt>Title</dt>
    <dd>Description</dd>
  </dl>
</main>
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

  • Related