50

I have a table with an Add button on the end. When you click this button I want a new table row to be created underneath the current one. I also want the input fields on this row to be blank. I am trying to do this using .clone() but it clones all the rows on the page. Please help. Thanks

Script

$("input.tr_clone_add")
        .live('click', function(){
              $(this).closest('.tr_clone')
                    .clone()
                    .insertAfter(".tr_clone")
         });

HTML

<table width="100%" border="0" cellspacing="0" cellpadding="0" id="table-data">
<tr>
<td>Name</td>
<td>Location</td>
<td>From</td>
<td>To</td>
<td>Add</td>
</tr>
<tr class="tr_clone">
<td><input type="text" autofocus placeholder="who" name="who" ></td>
<td><input type="text" autofocus placeholder="location" name="location" ></td>
<td><input type="text" placeholder="Start Date" name="datepicker_start" class="datepicker"></td>
<td><input type="text" placeholder="End Date" name="datepicker_end" class="datepicker"></td>
<td><input type="button" name="add" value="Add" class="tr_clone_add"></td>
</tr>
</table><!-- /table#table-data -->
insomniac
  • 11,146
  • 6
  • 44
  • 55
Clinton Green
  • 9,697
  • 21
  • 68
  • 103
  • I guess you also want the `name` parameter to be updated in order to avoid data conflicts (i.e. the values entered in the new row overwriting the values of the cloned row)...? – Tomm Nov 01 '11 at 02:38
  • Hi Tomm, I didn't think that name values would conflict, I was going to have to add a differentiator at some point though perhaps add a number to the tr class? – Clinton Green Nov 01 '11 at 02:43
  • 2
    I usually use a "template" to clone, which is styled to "display: none" via css. – hafichuk Nov 01 '11 at 02:47
  • 1
    A few things: (1) the `width`, `border`, `cellpadding`, and `cellspacing` attributes are deprecated in favor of CSS styles. Switch to CSS. (2) Use TH instead of TD elements for your table header cells. (3) You can't have more than one autofocus field. – Šime Vidas Nov 01 '11 at 02:49
  • @Šime Vidas thanks for picking that up. Cheers – Clinton Green Nov 01 '11 at 03:22

7 Answers7

80

Your problem is that your insertAfter:

.insertAfter(".tr_clone")

inserts after every .tr_clone:

the matched set of elements will be inserted after the element(s) specified by this parameter.

You probably just want to use after on the row you're duplicating. And a little .find(':text').val('') will clear the cloned text inputs; something like this:

var $tr    = $(this).closest('.tr_clone');
var $clone = $tr.clone();
$clone.find(':text').val('');
$tr.after($clone);

Demo: http://jsfiddle.net/ambiguous/LAECx/ or for a modern jQuery: http://jsfiddle.net/ambiguous/LAECx/3274/

I'm not sure which input should end up with the focus so I've left that alone.

mu is too short
  • 426,620
  • 70
  • 833
  • 800
  • 2
    @mzvarik Why? A leading `$` is a common reminder that you have elements wrapped in jQuery rather than just plain elements. Using them everywhere because your fingers think in PHP would be a bad habit but that's not the case here. – mu is too short Jan 15 '18 at 16:51
  • .live() is now deprecated, please don't use. – Sensoray Apr 12 '20 at 20:49
  • @Sensoray `live` was only in the original example from 2011. – mu is too short Apr 12 '20 at 21:19
  • 1
    I realize, I was just writing it in the comment so other people who viewed it would know. I was trying to figure out different methods, and tried live without knowing/checking the date of the answer posted since it was marked correct. Perhaps you can edit/add a note to it so other people who check it will know too :] – Sensoray Apr 12 '20 at 21:31
18

Here you go:

$( table ).delegate( '.tr_clone_add', 'click', function () {
    var thisRow = $( this ).closest( 'tr' )[0];
    $( thisRow ).clone().insertAfter( thisRow ).find( 'input:text' ).val( '' );
});

Live demo: http://jsfiddle.net/RhjxK/4/


Update: The new way of delegating events in jQuery is

$(table).on('click', '.tr_clone_add', function () { … });
Šime Vidas
  • 182,163
  • 62
  • 281
  • 385
  • What is the reason for `[0]` after `.closest('tr)` and, in the fiddle, `table = $( '#table-data' )[0]`? Why not just `var thisRow = $(this).closest('tr');` ? (Helpful example, btw, +1) – cssyphus Dec 22 '14 at 00:46
  • @gibberish Applying `[0]` on a jQuery object returns the first DOM element inside that jQuery object. This pattern is an old habit of mine - I like to store references to DOM objects inside variables directly. You can just leave it out in this case since we’re passing the `thisRow` variable into a new `$()` which doesn’t care if it receives DOM objects or jQuery objects containing DOM objects. – Šime Vidas Dec 22 '14 at 01:19
  • Very helpful, thanks Sime. I always watch for your answers. They are well written, clever and educative. Also, congrats on the increasing success of [webPlatformDaily](http://webplatformdaily.org/). I see that your insightful writing is appreciated by the Best of the Best. Well deserved; well done. – cssyphus Dec 22 '14 at 19:35
12

The code below will clone last row and add after last row in table:

var $tableBody = $('#tbl').find("tbody"),
$trLast = $tableBody.find("tr:last"),
$trNew = $trLast.clone();

$trLast.after($trNew);

Working example : http://jsfiddle.net/kQpfE/2/

maverickosama92
  • 2,685
  • 2
  • 21
  • 35
4

Try this variation:

$(".tr_clone_add").live('click', CloneRow);

function CloneRow()
{
    $(this).closest('.tr_clone').clone().insertAfter(".tr_clone:last");
}
Steve Wellens
  • 20,506
  • 2
  • 28
  • 69
2

Try this.

HTML

<!-- Your table -->
<table width="100%" border="0" cellspacing="0" cellpadding="0" id="table-data"> 
    <thead>
        <tr>
            <th>Name</th>
            <th>Location</th>
            <th>From</th>
            <th>To</th>
            <th>Add</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><input type="text" autofocus placeholder="who" name="who" ></td>
            <td><input type="text" autofocus placeholder="location" name="location" ></td>
            <td><input type="text" placeholder="Start Date" name="datepicker_start" class="datepicker"></td>
            <td><input type="text" placeholder="End Date" name="datepicker_end" class="datepicker"></td>
            <td><input type="button" name="add" value="Add" class="tr_clone_add"></td>
        </tr>
    <tbody>
</table>

<!-- Model of new row -->
<table id="new-row-model" style="display: none"> 
    <tbody>
        <tr>
            <td><input type="text" autofocus placeholder="who" name="who" ></td>
            <td><input type="text" autofocus placeholder="location" name="location" ></td>
            <td><input type="text" placeholder="Start Date" name="datepicker_start" class="datepicker"></td>
            <td><input type="text" placeholder="End Date" name="datepicker_end" class="datepicker"></td>
            <td><input type="button" name="add" value="Add" class="tr_clone_add"></td>
        </tr>
    <tbody>
</table>

Script

$("input.tr_clone_add").live('click', function(){
    var new_row = $("#new-row-model tbody").clone();
    $("#table-data tbody").append(new_row.html());
});
0

Try this code, I used the following code for cloning and removing the cloned element, i have also used new class (newClass) which can be added automatically with the newly cloned html

for cloning..

 $(".tr_clone_add").live('click', function() {
    var $tr    = $(this).closest('.tr_clone');
    var newClass='newClass';
    var $clone = $tr.clone().addClass(newClass);
    $clone.find(':text').val('');
    $tr.after($clone);
});

for removing the clone element.

$(".tr_clone_remove").live('click', function() { //Once remove button is clicked
    $(".newClass:last").remove(); //Remove field html
    x--; //Decrement field counter
});

html is as followinng

<tr class="tr_clone">
                       <!-- <td>1</td>-->
                        <td><input type="text" class="span12"></td>
                        <td><input type="text" class="span12"></td>
                        <td><input type="text" class="span12"></td>
                        <td><input type="text" class="span12"></td>
                        <td><input type="text" class="span10" readonly>
                        <span><a href="javascript:void(0);" class="tr_clone_add" title="Add field"><span><i class="icon-plus-sign"></i></span></a> <a href="javascript:void(0);" class="tr_clone_remove" title="Remove field"><span style="color: #D63939;"><i class="icon-remove-sign"></i></span></a> </span> </td> </tr>
Umair Mehmood
  • 514
  • 1
  • 11
  • 24
0

Is very simple to clone the last row with jquery pressing a button:

Your Table HTML:

<table id="tableExample">
    <thead>
        <tr>
            <th>ID</th>
            <th>Header 1</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>1</td>
            <td>Line 1</td>
        </tr>
    </tbody>
    <tfoot>
        <tr>
            <td colspan="2"><button type="button" id="addRowButton">Add row</button></td>
        </tr>
    </tfoot>
</table>

JS:

$(document).on('click', '#addRowButton', function() {
    var table = $('#tableExample'),
        lastRow = table.find('tbody tr:last'),
        rowClone = lastRow.clone();

    table.find('tbody').append(rowClone);
});

Regards!

Radames E. Hernandez
  • 4,235
  • 27
  • 37