Tom Hanks
Tom Hanks

Reputation: 614

For Loop is stopping at 1, not counting elements added to DOM

I am trying to make it so each child input added have the same event listener as the parent input.

Snippet (also on Codepen):

var main = document.getElementById("main").getElementsByTagName("a");

var button = document.createElement('input');

// Loop over A tags in #main
for (var i = 0; i < main.length; i++) {
  // # of A tags
  console.log(main.length);
  // Event listener per # of A tags
  main[i].addEventListener("click",function(e){
    // Clone parentElement #main
    var node = e.target.parentElement;
    var clone = node.cloneNode(true);
    // Append to DOM
    document.getElementById('main').appendChild(clone);
  });
}
<div id="main">
  <div class="input__container">
  <label>Input</label>
  <input placeholder="Placeholder..." class="input" id="" name="" type="text"/>
  <a class="btn">+</a>
  </div>
</div>

Upvotes: 0

Views: 53

Answers (4)

Jordan Soltman
Jordan Soltman

Reputation: 3883

I wouldn't say this is necessarily the best way to achieve this, but trying to stick with your general strategy here:

let cloneSelf = function(e) {
  var parent = e.target.parentElement;
  var clone = parent.cloneNode(true);
  // Event listeners are not cloned with "cloneNode" so we have to do it manually.
  clone.getElementsByTagName("a")[0].addEventListener("click", cloneSelf);
  document.getElementById('main').appendChild(clone);
}

// Get the first link, and add the event listener
var firstLink = document.getElementById("main").getElementsByTagName("a")[0];

firstLink.addEventListener("click", cloneSelf);
<div id="main">
  <div class="input__container">
    <label>Input</label>
    <input placeholder="Placeholder..." class="input" id="" name="" type="text" />
    <a class="btn">+</a>
  </div>
</div>

Upvotes: 0

T.J. Crowder
T.J. Crowder

Reputation: 1074178

You're not adding any a elements to the DOM within your for loop, so it stops when it's done with the ones within #main that are there when it runs (there's only one).

You probably want to use event delegation on main instead: You handle the click on main, but then only do something with it if the click passed through an a.btn; see comments:

// Get the element, not the `a` elements within it
var main = document.getElementById("main")

// Listen for clicks on it
main.addEventListener("click", function(e) {
  // If this click passed through an `a.btn` within #main (this``)...
  var btn = e.target.closest("a.btn");
  if (btn && this.contains(btn)) {
    // Clone the btn's parentElement, append to #main
    var node = btn.parentElement;
    var clone = node.cloneNode(true);
    main.appendChild(clone);
  }
});
<div id="main">
  <div class="input__container">
    <label>Input</label>
    <!-- Note that `id` and `name` are not allowed to be blank; just leave them off -->
    <input placeholder="Placeholder..." class="input" type="text"/>
    <a class="btn">+</a>
  </div>
</div>

Upvotes: 0

furkanhb
furkanhb

Reputation: 9

cloneNode method does not copy event listeners.

Cloning a node copies all of its attributes and their values, including intrinsic (in–line) listeners. It does not copy event listeners added using addEventListener() or those assigned to element properties (e.g. node.onclick = fn).

cloneNode description

Upvotes: 0

Patrick Roberts
Patrick Roberts

Reputation: 51846

Instead of trying to duplicate the event handler, use a single delegated event handler attached to #main:

var main = document.getElementById("main");

main.addEventListener("click", function(e) {
  // Delegated event handler returning early if wrong target
  if (!e.target.matches(".btn")) return;
  // Clone parentElement .input__container
  var node = e.target.parentElement;
  var clone = node.cloneNode(true);
  // Append to main
  this.appendChild(clone);
});
<div id="main">
  <div class="input__container">
    <label>Input</label>
    <input placeholder="Placeholder..." class="input" id="" name="" type="text" />
    <a class="btn">+</a>
  </div>
</div>

Upvotes: 2

Related Questions