jQuery 'Add row' function counter issues

I have a very simple form on my website.

The bug: I click the ‘Yes‘ radio button then click ‘Add 1 more‘ 3 times and instead of having 4 rows in total, I have about 9(?)

Give it a try in the JS Fiddle here. I’ve also attached here in the post.

I’m assuming it’s my Counter but been racking my head all morning with no joy.

Many thanks for any guidance here.

$(function() {
    // Initially hide both divs
    $(".bulk").hide();
    $(".individual").hide();
    // Listen for changes in the radio button selection
    $("input[name='bulkPayments']").change(function() {
        if ($(this).val() === "Yes") {
            // Show the bulk div and hide the individual div
            $(".bulk").show();
            $(".individual").hide();
        } else if ($(this).val() === "No") {
            // Show the individual div and hide the bulk div
            $(".bulk").hide();
            $(".individual").show();
        }
    });
});
$(document).ready(function() {
    // Initialize the counter for generating unique names and IDs
    var counter = 1;
    // Add more sets when the "Add 1 more" button is clicked
    $("#addMore").click(function(event) {
        event.preventDefault(); // Prevent the default form submission
        // Clone the "bulk" section and update the attributes
        var newBulkSection = $(".bulk:first").clone();
        // Increment the counter for the next set and update the IDs and names
        counter++;
        newBulkSection.find("input[type=text]").attr("id", "clientName" + counter).attr("name", "clientName" + counter);
        newBulkSection.find("input[type=file]").attr("id", "attachments" + counter).attr("name", "attachments" + counter);
        // Clear input values in the new section (optional)
        newBulkSection.find("input[type=text]").val("");
        newBulkSection.find("input[type=file]").val("");
        // Append the newly modified section to the container
        $("#bulkContainer").append(newBulkSection);
        // Show the newly added section
        newBulkSection.show();
    });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<form action="" enctype="multipart/form-data" method="post">
        <div class="form-group">
            <label>Bulk Payments *:</label>
            <div class="radio">
                <label><input name="bulkPayments" type="radio" value="Yes"> Yes</label>
            </div>
            <div class="radio">
                <label><input name="bulkPayments" type="radio" value="No"> No</label>
            </div>
        </div>
        <div class="bulk" id="bulkContainer" style="display:none">
            <div class="row">
                <div class="col-md-6">
                    <div class="form-group">
                        <label for="clientName1">Client Name *:</label> <input autocomplete="one-time-code" class="form-control" id="clientName1" name="clientName1" placeholder="" required="" type="text">
                    </div>
                </div>
                <div class="col-md-6">
                    <div class="form-group">
                        <label for="attachments1">Attachment:</label> <input class="form-control-file" id="attachments1" name="attachments1" type="file">
                    </div>
                </div>
            </div>
        </div><button class="btn" id="addMore">Add 1 more</button>
    </form>

>Solution :

The issue is because #bulkContainer and .bulk are the same element, so when you clone .bulk:first you’re cloning the entire container with all previous clones within it.

To fix the issue, remove the .bulk class from #bulkContainer and add it to a new child div, like this:

$(function() {
  // Initially hide both divs
  $("#bulkContainer").hide();
  $(".individual").hide();

  // Listen for changes in the radio button selection
  $("input[name='bulkPayments']").change(function() {
    if ($(this).val() === "Yes") {
      // Show the bulk div and hide the individual div
      $("#bulkContainer").show();
      $(".individual").hide();
    } else if ($(this).val() === "No") {
      // Show the individual div and hide the bulk div
      $("#bulkContainer").hide();
      $(".individual").show();
    }
  });

  // Initialize the counter for generating unique names and IDs
  var counter = 1;

  // Add more sets when the "Add 1 more" button is clicked
  $("#addMore").click(function(event) {
    event.preventDefault(); // Prevent the default form submission
    // Clone the "bulk" section and update the attributes
    var newBulkSection = $(".bulk:first").clone();
    // Increment the counter for the next set and update the IDs and names
    counter++;
    newBulkSection.find("input[type=text]").attr("id", "clientName" + counter).attr("name", "clientName" + counter);
    newBulkSection.find("input[type=file]").attr("id", "attachments" + counter).attr("name", "attachments" + counter);
    // Clear input values in the new section (optional)
    newBulkSection.find("input[type=text]").val("");
    newBulkSection.find("input[type=file]").val("");
    // Append the newly modified section to the container
    $("#bulkContainer").append(newBulkSection);
    // Show the newly added section
    newBulkSection.show();
  });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<form action="" enctype="multipart/form-data" method="post">
  <div class="form-group">
    <label>Bulk Payments *:</label>
    <div class="radio">
      <label><input name="bulkPayments" type="radio" value="Yes"> Yes</label>
    </div>
    <div class="radio">
      <label><input name="bulkPayments" type="radio" value="No"> No</label>
    </div>
  </div>
  <div id="bulkContainer" style="display:none">
    <div class="bulk">
      <div class="row">
        <div class="col-md-6">
          <div class="form-group">
            <label for="clientName1">Client Name *:</label> <input autocomplete="one-time-code" class="form-control" id="clientName1" name="clientName1" placeholder="" required="" type="text">
          </div>
        </div>
        <div class="col-md-6">
          <div class="form-group">
            <label for="attachments1">Attachment:</label> <input class="form-control-file" id="attachments1" name="attachments1" type="file">
          </div>
        </div>
      </div>
    </div>
  </div>
  <button class="btn" id="addMore">Add 1 more</button>
</form>

Also, as an aside, note that creating incremental id attributes using a counter variable is not ideal practice. I would strongly suggest you remove that logic and use common classes instead. If you need to identify a specific group of the cloned HTML, use its index.

Here’s a demonstration of how to do that:

$(function() {
  const $bulkContainer = $("#bulkContainer");
  const $individual = $('.individual');

  $("input[name='bulkPayments']").on('change', e => {
    const value = $(e.target).val();
    $bulkContainer.toggle(value === "Yes");
    $individual.toggle(value !== "Yes");
  });

  $("#addMore").on('click', e => {
    e.preventDefault();
    var $newBulkSection = $(".bulk:first").clone().insertAfter('.bulk:last');
    $newBulkSection.find("input[type=text], input[type=file]").val("");
  });
});
#bulkContainer,
.individual {
  display: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<form action="" enctype="multipart/form-data" method="post">
  <div class="form-group">
    <label>Bulk Payments *:</label>
    <div class="radio">
      <label><input name="bulkPayments" type="radio" value="Yes"> Yes</label>
    </div>
    <div class="radio">
      <label><input name="bulkPayments" type="radio" value="No"> No</label>
    </div>
  </div>
  <div id="bulkContainer">
    <div class="bulk">
      <div class="row">
        <div class="col-md-6">
          <div class="form-group">
            <label for="clientName1">Client Name *:</label>
            <input autocomplete="one-time-code" class="form-control" name="clientName" placeholder="" required="" type="text" />
          </div>
        </div>
        <div class="col-md-6">
          <div class="form-group">
            <label for="attachments1">Attachment:</label>
            <input class="form-control-file" name="attachments" type="file" />
          </div>
        </div>
      </div>
    </div>
    <button class="btn" id="addMore">Add 1 more</button>
  </div>
</form>

Leave a Reply