3

Suppose I have this form with indexed input fields username and level:

<form>
 <table>
  <tr class="trToClone">
    <td>
      <label>Username:</label>
      <input type="text" name="username[0]" />
    </td>
    <td>
      <label>Level:</label>
      <select name="level[0]">
        <option value="">---</option>
        <option value="a">A</option>
        <option value="b">B</option>
        <option value="c">C</option>
      </select>
    </td>
    <td><input type="button" class="addField" value="Add" /></td>
  </tr>
 </table>  
</form>

The row can be repeated using this jQuery:

$("input.addField").on('click', function() {
  var $tr = $(this).closest('.trToClone');
  var $clone = $tr.clone();
  $clone.find(':text').val('');
  $tr.after($clone);
});

Now for every subsequent row I add, I want to increase the indices of the name attribute (i.e. username[1],level[1]; username[2],level[2]; and so on...). How can I do this? I've looked for possible solutions, but to no avail.

3
  • Do you want to have multiple buttons are just one at the end which will always add element to the end. Because currently you will have multiple buttons and they will not work correctly if you try to add element in between to buttons. As well clone with setting it parameters to true will not clone your click handler for the button. Commented Nov 15, 2017 at 12:28
  • One at the end, preferably. Didn't work in jsfiddle when I tried it like that, hence this way. Commented Nov 15, 2017 at 12:36
  • Then pull out the button out of that table row, maybe the best right after closing table tag and try the code that @wscourge has written. This way you don't have to worry about event bindings and you just replicate static element with few changes Commented Nov 15, 2017 at 12:45

4 Answers 4

2

Specify new index with $('.trToClone').length, modify it on each element with name attribute with jQuery .attr() method:

$("input.addField").on('click', function() {
  var $tr = $(this).closest('.trToClone');
  var $clone = $tr.clone(true, true);
  
  var $names = $clone.find('[name]');
  var trIndex = $('.trToClone').length;
  
  $names.each(function(index, element) {
     
    var newName = $(element).attr('name').replace(/[0-9]/g, trIndex);
   
    $(element).attr('name', newName);
    
    console.log($(element).attr('name'));
  
  });
  
  $clone.find(':text').val('');
  $tr.after($clone);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form>
 <table>
  <tr class="trToClone">
    <td>
      <label>Username:</label>
      <input type="text" name="username[0]" />
    </td>
    <td>
      <label>Level:</label>
      <select name="level[0]">
        <option value="">---</option>
        <option value="a">A</option>
        <option value="b">B</option>
        <option value="c">C</option>
      </select>
    </td>
    <td><input type="button" class="addField" value="Add" /></td>
  </tr>
 </table>  
</form>

Sign up to request clarification or add additional context in comments.

1 Comment

I think he needs to clone element with its bindings as well. So if you want to clone your element and have button retain its click handler he should use .clone(true, true) as stated in the documentation api.jquery.com/clone
0

UPDATE: changing name attributes dynamically.

you can use a counter for counting your clicks! You have to move the "add" click button out of the table row. HTML:

<form>
 <input type="button" class="addField" value="Add" />
 <table>
  <tr class="trToClone">
    <td>
      <label>Username:</label>
      <input type="text" name="username[0]" />
    </td>
    <td>
      <label>Level:</label>
      <select name="level[0]">
        <option value="">---</option>
        <option value="a">A</option>
        <option value="b">B</option>
        <option value="c">C</option>
      </select>
    </td>
    <td></td>
  </tr>
 </table> 
</form>

JS:

var counter = 0;
$("input.addField").on('click', function() {
    counter++;
  var $tr = $('.trToClone:eq(0)');
  var $clone = $tr.clone();
  var newTextName = $clone.find(':text').attr('name').replace(/\[(\d)+\]/,'[+ counter +']');
  $clone.find(':text').attr('name',newTextName);
  $clone.find('.dropdown').attr('name','level['+ counter + ']');
  $tr.parent().append($clone);
});

check out this fiddle: https://jsfiddle.net/gknrfw1g/2/

3 Comments

Cool! I'll try this out on my project and let you know.
This works fine for just one text input field. What if I have, say, "firstName" as another text field? Wouldn't $clone.find(':text').attr('name','username['+ counter + ']'); change that field name to "username" as well? How would I solve this issue?
I made a change to the answer! you have to use a regex to recognize the "[x]" in the name and change it through [y].
0

$('.addField').click(function(){
  var count = $('#btnIncrease').val();
  var $tr = $(this).closest('.trToClone');
  var $clone = $tr.clone();
  count++;
  $('#btnIncrease').val(count);
  $clone.find(':text').val('');
  $clone.find(':text').attr('name', 'username[' + count + ']');
  $tr.after($clone); 
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
  <tr class="trToClone">
    <td>
      <label>Username:</label>
      <input type="text" name="username[0]" />
    </td>
    <td>
      <label>Level:</label>
      <select name="level[0]">
        <option value="">---</option>
        <option value="a">A</option>
        <option value="b">B</option>
        <option value="c">C</option>
      </select>
    </td>
    <td><input type="button" class="addField" value="Add" /></td>
  </tr>
 </table>
 
 <input type="hidden" id="btnIncrease" value="0" />

This would work for you.

Comments

0

For adding the name attribute you first need to find the index of current row and then you can add 1 to the index and again update the name attribute for both text and select list. Try with the code below-

Note- You should also hide the add button from previous row and bind the click function again for the newly cloned row.

 $("input.addField").on('click', function() {
      var $tr = $(this).closest('.trToClone');
      var $clone = $tr.clone();
      var lastIndexName= $clone.find(':text').attr("name").split('[');
      var lastIndex=parseInt(lastIndexName[1].substring(0,1));
      var updatedNameValue="username["+(lastIndex+1)+"]";
      $clone.find(':text').attr("name",updatedNameValue);
      $clone.find(':text').val('');
      $clone.find('select').attr("name","level["+(lastIndex+1)+"]")
      $tr.after($clone);
    });

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.