Search code examples
javascriptjqueryformsclone

Adding additional input text after cloning JQuery


I'm relatively new to Javascript/jQuery and I'm trying to clone a form to record scores. I can add as many input as I want to the pre-cloned form but I can't add, nor remove, any additional text inputs in the subsequent cloned forms.

Let's say before I add a pre-requisite, I placed in 5 input boxes. In that first form, I can remove and add as many input boxes as I want.

Now let's say I add a prequisite, it will clone the first form, but in the cloned form I cannot add nor remove any of the input boxes. That is my issue.

At this point I am stumped on how to fix this.

$(document).ready(function() {
  var max_fields = 10;
  var wrapper = $(".form-input");
  var add_button = $(".add_item");

  var x = 1;
  $(add_button).click(function(e) {
    e.preventDefault();
    if (x < max_fields) { //max input box allowed
      x++; //text box increment
      $(wrapper).append('<div><input type="text" name="items[]"/><a href="#" class="remove_field">X</a></div>'); //add input box
    }
  });

  $(wrapper).on("click", ".remove_field", function(e) { //user click on remove text
    e.preventDefault();
    $(this).parent('div').remove();
    x--;
  })
});

//Write code to clone form here, but set everything to default and add
//a button to remove any prerequisites.

$(document).ready(function() {
  var ctr = 1;
  $(".add_req").click(function() {
    $(".myForm").eq(0)
      .clone()
      .find("input")
      .val("")
      .end()
      .show()
      .insertAfter(".myForm:last");
  });
  $('.all').on('click', ".remove-req", function() {
    $(this).closest('.myForm').remove();
  });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<head>
  <meta charset=utf-8 />
  <title>JS Bin</title>
  <link rel="stylesheet" href="style.css">
</head>

<body>
  <div class="all">
    <button class="add_req">Add Preq-Requisite</button>
    <form class="myForm">
      <section class="selection-menus">

        <select name="major" class="major">
          <option selected="selected">SELECT MAJOR</option>
          <option value="CS">Computer Science</option>
          <option value="CIS">Computer Information Systems</option>
        </select>

        <select name="course-no" class="course-no">
          <option value="CS_000">SELECT COURSE</option>
          <option value="CS_140">140</option>
          <option value="CS_210">210</option>
          <option value="CS_220">220</option>

          <!--THERE IS NO CIS DATA, THIS IS JUST FOR FUNCTIONALITY-->
          <option value="CIS_000">SELECT COURSE</option>
          <option value="CIS_315">315</option>
          <option value="CIS_330">330</option>
          <option value="CIS_497">497</option>
        </select>

        <button class="add_item">Add Item</button>

      </section>

      <div class="form-input">
        <div><input type="text" name="items[]"></div>
      </div>
      <span class="remove-req">Remove Req</span>
    </form>
  </div>
</body>


Solution

  • It has to do with the way you select your wrapper element.

    When the page loads you get the wrapper element with $(".form-input");. This means you have now selected the elements with the .form-input class that are currently on the page. This works fine.

    However, from here you clone your form and create a second element with the .form-input, that comes from the original form. But the difference here is that the wrapper variable never found this second .form-input because it didn't exist yet. Same will count for all consequent .form-input elements.

    A fix for this is to change the event listener for .remove_field. Instead of listening to only the first wrapper, listen on the document for the click. All clicks eventually bubble to the document, unless they're intercepted and stopped.

    $(document).ready(function() {
      var max_fields = 10;
      var wrapper = $(".form-input");
      var add_button = $(".add_item");
    
      var x = 1;
      $(document).on('click', '.add_item', function(e) {
        e.preventDefault();
        var $this = $(this);
        var $formInput = $this.parent().next();
        
        if (x < max_fields) { //max input box allowed
          x++; //text box increment
          $formInput.append('<div><input type="text" name="items[]"/><a href="#" class="remove_field">X</a></div>'); //add input box
        }
      });
    
      $(document).on("click", ".remove_field", function(e) { //user click on remove text
        e.preventDefault();
        $(this).parent('div').remove();
        x--;
      })
    });
    
    //Write code to clone form here, but set everything to default and add
    //a button to remove any prerequisites.
    
    $(document).ready(function() {
      var ctr = 1;
      $(".add_req").click(function() {
        $(".myForm").eq(0)
          .clone()
          .find("input")
          .val("")
          .end()
          .show()
          .insertAfter(".myForm:last");
      });
      $('.all').on('click', ".remove-req", function() {
        $(this).closest('.myForm').remove();
      });
    });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <head>
      <meta charset=utf-8 />
      <title>JS Bin</title>
      <link rel="stylesheet" href="style.css">
    </head>
    
    <body>
      <div class="all">
        <button class="add_req">Add Preq-Requisite</button>
        <form class="myForm">
          <section class="selection-menus">
    
            <select name="major" class="major">
              <option selected="selected">SELECT MAJOR</option>
              <option value="CS">Computer Science</option>
              <option value="CIS">Computer Information Systems</option>
            </select>
    
            <select name="course-no" class="course-no">
              <option value="CS_000">SELECT COURSE</option>
              <option value="CS_140">140</option>
              <option value="CS_210">210</option>
              <option value="CS_220">220</option>
    
              <!--THERE IS NO CIS DATA, THIS IS JUST FOR FUNCTIONALITY-->
              <option value="CIS_000">SELECT COURSE</option>
              <option value="CIS_315">315</option>
              <option value="CIS_330">330</option>
              <option value="CIS_497">497</option>
            </select>
    
            <button class="add_item">Add Item</button>
    
          </section>
    
          <div class="form-input">
            <div><input type="text" name="items[]"></div>
          </div>
          <span class="remove-req">Remove Req</span>
        </form>
      </div>
    </body>

    I would recommend that you didn't clone the entire <form> element, as I can imagine that all data has to be sent as a whole. But each <form> element is its own entity and won't work together with other forms.