JavaScript add element method doubling not adding

124 Views Asked by At

I'm trying to use JavaScript to create copies of a div element when a button is clicked. I'm using the .cloneNode() method, but it's multiplying the results.

Initially there is one instance of the element on the page; on click that doubles to 2, however on the next click it doubles again to 4. I need it to add individually, so click->3,click->4, etc.

My codepen is: https://codepen.io/anon_guy/pen/VMZWWW

HTML:

<div class="panel panel-default">
  <div class="panel-heading">
  </div>
  <div class="panel-body">
    <form action="<?php echo $action; ?>" method="post" enctype="multipart/form-data" id="form-event" class="form-horizontal">
      <div class="col-sm-4">
        <label>name</label>
        <input type="text" name="name" value="name" placeholder="name" id="name" class="form-control" />
      </div>
      <div class="col-sm-4">
        <label>address</label>
        <input type="text" name="address" value="address" placeholder="address" id="address" class="form-control" />
      </div>
      <div class="col-sm-4">
        <label>phone</label>
        <input type="text" name="phone" value="phone" placeholder="phone" id="phone" class="form-control" />
        <div class="text-danger"></div>
      </div>

    </form>
  </div>
  <div class="row">
  <div class="add_component">
    <button id='launch'>Add Component</button>
  </div>
  </div>
</div>
<div class="wrapper">
  <div class="panel panel-default " id="addon">
    <div class="panel-heading">
    </div>
    <div class="panel-body">
      <form action="<?php echo $action; ?>" method="post" enctype="multipart/form-data" id="form-event" class="form-horizontal">
        <div class="col-sm-6">
          <label>component</label>
          <input type="text" name="component" value="component" placeholder="component" id="component" class="form-control" />
        </div>

      </form>
    </div>
  </div>
</div>

JS:

document.getElementById('launch').onclick = function() {
    var addOnDiv = document.getElementById('addon');
    var clonedNode = addOnDiv.cloneNode(true);
    addOnDiv.appendChild(clonedNode );
}
4

There are 4 best solutions below

0
intentionally-left-nil On BEST ANSWER

This happens because cloneNode clones both the node as well as any children that it includes.

After you clone the addon div, you then append your new clone to the child of addon. Therefore, it is now part of addon and both nodes will be copied in each subsequent add.

The easiest fix is to just append the cloned node as a sibling of addon instead of as a child. You simply need to change

addOnDiv.appendChild(clonedNode );

to

addOnDiv.parentNode.appendChild(clonedNode );

in your JS file

0
Strake On

Take a look at what document.getElementById('addon') is selecting by writing console.log(document.getElementById('addon')). More to the point you are appending <div id="addon"> inside the existing addon element using appendChild. Thus when you next select addon you have selected an element with the another clone of addon nested inside of it. This is causing the multiplication you mentioned.

You'll probably want to append to the parentnode using: addOnDiv.parentNode.appendChild(clonedNode);

Also note that you have multiple elements with the same id of addon. This is allowable but may not perform as you expect.

0
freginold On

Each time you clone the addOn div, you're making it bigger. So the second time you clone it, you're cloning the main div plus its child that you added last time, and the next time you'll be cloning the div which now has another child, etc.

To get around this problem, make sure you are only cloning one div at a time. See this code for a solution:

var doneOnce = false;    // flag

document.getElementById('launch').onclick = function() {
  var addOnDiv = document.getElementById('addon');
  var clonedNode = addOnDiv.cloneNode(true);
  doneOnce ? clonedNode = addOnDiv.childNodes[addOnDiv.childNodes.length - 1].cloneNode(true) : doneOnce = true;
  addOnDiv.appendChild(clonedNode);
}
<div class="panel panel-default">
  <div class="panel-heading">
  </div>
  <div class="panel-body">
    <form action="<?php echo $action; ?>" method="post" enctype="multipart/form-data" id="form-event" class="form-horizontal">
      <div class="col-sm-4">
        <label>name</label>
        <input type="text" name="name" value="name" placeholder="name" id="name" class="form-control" />
      </div>
      <div class="col-sm-4">
        <label>address</label>
        <input type="text" name="address" value="address" placeholder="address" id="address" class="form-control" />
      </div>
      <div class="col-sm-4">
        <label>phone</label>
        <input type="text" name="phone" value="phone" placeholder="phone" id="phone" class="form-control" />
        <div class="text-danger"></div>
      </div>

    </form>
  </div>
  <div class="row">
    <div class="add_component">
      <button id='launch'>Add Component</button>
    </div>
  </div>
</div>
<div class="wrapper">
  <div class="panel panel-default " id="addon">
    <div class="panel-heading">
    </div>
    <div class="panel-body">
      <form action="<?php echo $action; ?>" method="post" enctype="multipart/form-data" id="form-event" class="form-horizontal">
        <div class="col-sm-6">
          <label>component</label>
          <input type="text" name="component" value="component" placeholder="component" id="component" class="form-control" />
        </div>

      </form>
    </div>
  </div>
</div>

EDIT:

See @AnilRedshift's answer for a much cleaner and simpler solution.

0
BILAL AHMAD On

The problem is that you are cloning from and appending to the same div. So initially the div has one component. once you clone the div containing one it becomes two, when you clone the div containing two components and append the same to it, the total number of components become four and so on.

I have edited the code, instead of appending to the same container time and again, i am appending to the parent container which i have assigned an ID "mContainer". You can change the code as per your requirement. Please refer to the updated code below.

https://codepen.io/bilaleme90/pen/eGYvRd

JS and HTML:

document.getElementById('launch').onclick = function() {
  var addOnDiv = document.getElementById('addon');
  var container = document.getElementById('mContainer')
  var clonedNode = addOnDiv.cloneNode(true);
  container.appendChild(clonedNode);
}
<div class="panel panel-default">
  <div class="panel-heading">
  </div>
  <div class="panel-body">
    <form action="<?php echo $action; ?>" method="post" enctype="multipart/form-data" id="form-event" class="form-horizontal">
      <div class="col-sm-4">
        <label>name</label>
        <input type="text" name="name" value="name" placeholder="name" id="name" class="form-control" />
      </div>
      <div class="col-sm-4">
        <label>address</label>
        <input type="text" name="address" value="address" placeholder="address" id="address" class="form-control" />
      </div>
      <div class="col-sm-4">
        <label>phone</label>
        <input type="text" name="phone" value="phone" placeholder="phone" id="phone" class="form-control" />
        <div class="text-danger"></div>
      </div>

    </form>
  </div>
  <div class="row">
    <div class="add_component">
      <button id='launch'>Add Component</button>
    </div>
  </div>
</div>
<div class="wrapper" id="mContainer">
  <div class="panel panel-default " id="addon">
    <div class="panel-heading">
    </div>
    <div class="panel-body">
      <form action="<?php echo $action; ?>" method="post" enctype="multipart/form-data" id="form-event" class="form-horizontal">
        <div class="col-sm-6">
          <label>component</label>
          <input type="text" name="component" value="component" placeholder="component" id="component" class="form-control" />
        </div>

      </form>
    </div>
  </div>
</div>