javascriptclonenode

Clone <div> and change onclick code of inner button


I have a div with id="add-dependent" including 2 rows and a button (add dependent) inside of the div. When "add dependent" button is clicked, the first row would be cloned and insert before (add dependent) button. Actually I have another button outside of the div called (add applicant) and by clicking it, whole of the div would be cloned and added before (add applicant) button. my code is like this :

 let nextLabel=2
    let nextId=1
function addApplicant(){
            var elem= document.querySelector("#add-dependent");
            var clone=elem.cloneNode(true);
            var add= document.getElementById("add-applicant");
    clone.id = "add-dependent"+nextLabel;
            elem.parentElement.insertBefore(clone,add);
      var label = clone.querySelector("label");
  label.innerHTML = '<button  class="close remove"  onClick="$(this).parent().parent().parent().parent().remove()">x</button>' + "Applicant " + (nextLabel++) ;
     
        } 
    
  
        
        
    
        function addDependent(){
            var elem= document.querySelector(".dependent");
            var clone=elem.cloneNode(true);
            var add= document.getElementById("dependent");
            elem.parentElement.insertBefore(clone,add);
            var label=clone.querySelector('label');
            label.innerHTML= '<button id="btn" name="btn" type="button" class="close float-left" style="font-size:12px;" onClick="$(this).parent().parent().parent().remove();" >x</button>';
             
        }
        
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="add-dependent">
        <div class="form-row dependents">
            <div>
                <label class="text-left" contenteditable="true">Applicant 1: </label>
            </div>
            <div >
                  <input   type="number" placeholder="age">
            </div>
        </div>
        <div class="form-row dependent">
            <div>
                <button id="btn" name="btn" type="button" class="close " onClick="$(this).parent().parent().remove();" >x</button>
            </div>
            <div>
                  <input  type="number"  placeholder="age">
            </div>
        </div>
        <button id="dependent" onClick="addDependent()">Add dependent</button>
    </div>
  
    <button id="add-applicant" onClick="addApplicant()">Add applicant</button>

my problem is when i click on (add dependent) in cloned div, the row is added to main div not cloned one. hope to here you soon. Thanks a lot


Solution

  • There are many changes I made to your code and I'll try to explain them here. When you're working with duplicating, appending, removing etc, id's can become difficult to work with - you can't have duplicates of IDs and your code then has to track which id is affected by which button etc.

    Its much easier to work with relative paths. For instance when you want to add a dependent, it's easier to say 'find a dependent input to clone and place it inside the container from where I clicked this add-dependent button' - and walla no need for ids. To find the relative div's, I used a combination of event.target, closest() and querySelctor - like this:

    e.target
       .closest('.add-applicant-container')
       .querySelector('.dependents')
       .append(clone);
    

    This says Starting from the button I clicked, find the closest '.add-applicant-container' and inside that find the first '.dependents' and place our clone right after that

    Finally, the buttons. Because you're creating and destroying these buttons in the process, it's best to set up a listener on document and test to see which button was clicked. This is called event delegation. For the dependent delete button, we only need to find the relative element and delete it so:

    if (e.target.classList.contains('close')) {
        e.target.closest('.dependent-container').remove()
      }
    

    let nextLabel = 2
    let nextId = 1
    document.addEventListener('click', function(e) {
      if (e.target.classList.contains('add-applicant')) {
        addApplicant(e)
      } else if (e.target.classList.contains('btn-dependent')) {
        addDependent(e) 
      } else if (e.target.classList.contains('remove-applicant')) {
        e.target.closest('.add-applicant-container').remove()
      } else if (e.target.classList.contains('close')) {
        e.target.closest('.dependent-container').remove()
      }
    })
    
    function addApplicant(e) {
      let applicant = document.querySelector('.add-applicant-container')
      var clone = applicant.cloneNode(true);
      clone.id = "add-dependent" + nextLabel;
      clone.querySelectorAll('.dependent-container').forEach((el, i) => {
        if (i !== 0) el.remove()
      })
      applicant.parentElement.insertBefore(clone, e.target);
      var label = clone.querySelector("label");
      label.innerHTML = '<button  class="close remove-applicant">x</button>' + "Applicant " + (nextLabel++);
    }
    
    function addDependent(e) {
      let dependent = document.querySelector('.dependent-container')
      var clone = dependent.cloneNode(true);
      e.target.closest('.add-applicant-container').querySelector('.dependents').append(clone);
      // var label = clone.querySelector('label');
      //  label.innerHTML = '<button id="btn" name="btn" type="button" class="close float-left" style="font-size:12px;" >x</button>';
    
    }
    .add-applicant-container{
    padding:10px;
    }
    
    .dependent-container{
    padding:5px 0 ;
    
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <div class="add-applicant-container">
      <div class="form-row dependents">
        <div>
          <label class="text-left" contenteditable="true">Applicant 1: </label>
        </div>
        <div>
          <input type="number" placeholder="applicant age">
        </div>
      </div>
      <div class="form-row dependent-container">
        <div>
          <input type="number" placeholder="dependent age"> <button id="btn" name="btn" type="button" class="close ">x</button>
        </div>
      </div>
      <button class="btn-dependent">Add dependent</button>
    </div>
    
    <button class="add-applicant">Add applicant</button>