How to clone two columns in a table using jQuery

2019-02-23 00:31发布

问题:

I am trying to clone 2 columns from a table to a new table using jQuery. The source table is below:

<table id="sourceT">
    <tr>
        <td>Col 1</td>
        <td>Col 2</td>
        <td>Col 3</td>
    </tr>
    <tr>
        <td>Col 1 - value</td>
        <td>Col 2 - value</td>
        <td>Col 3 - value</td>
    </tr>
</table>
<table id="targetT"></table>

What I tried is,

$("#sourceT").find("tr > td:nth-child(1), tr > td:nth-child(2)").each(function () {
    $("#targetT").append($("<tr></tr>").append($(this).clone()));
});

I only want to copy first and second columns to a new table like

<table id="targetT">
    <tr>
        <td>Col 1</td>
        <td>Col 2</td>
   </tr>
    <tr>
        <td>Col 1 - value</td>
        <td>Col 2 - value</td>
   </tr>
</table>

But using those jquery, I only get like below;

<table id="targetT">
    <tr>
        <td>Col 1</td>
    </td>
    <tr>
        <td>Col 1 - value</td>
    </td>
    <tr>
        <td>Col 2</td>
    </td>
    <tr>
        <td>Col 2 - value</td>
    </td>
</table>

I am not trying to loop all the tr and td's from source table. Coz, my source table is going to be more than thousands rows and more than 50 cols. Anyone has got any ideas?

回答1:

I'd probably do something like this:

var $target = $("#targetT");
$("#sourceT tr").each(function() {
    var $tds = $(this).children(),
        $row = $("<tr></tr>");
    $row.append($tds.eq(0).clone()).append($tds.eq(1).clone()).appendTo($target);
});

Demo: http://jsfiddle.net/HwzQg/

That is, loop through each row of the source table and just copy the required columns. This way it doesn't matter if the required columns are adjacent, and it is easy to change the code to copy more columns if your requirement changes. In fact you could easily encapsulate it in a function that takes the source and target tables as parameters along with a list of which column numbers to copy:

function copyColumns(srcTableId, targetTableId) {
    var colNos = [].slice.call(arguments,2),
        $target = $("#" + targetTableId);
    $("#" + srcTableId + " tr").each(function() {
        var $tds = $(this).children(),
            $row = $("<tr></tr>");
        for (var i = 0; i < colNos.length; i++)
            $row.append($tds.eq(colNos[i]).clone());
        $row.appendTo($target);
    });
}

copyColumns("sourceT", "targetT", 0, 1);
// NOTE that this allows you to easily re-order the columns as you copy them:
copyColumns("sourceT", "targetT", 1, 0, 2);

This uses arguments to let you have any number of column numbers as separate arguments, but of course you could modify it to instead accept an array of column numbers. Whatever works for you.

Demo: http://jsfiddle.net/HwzQg/1/

"I am not trying to loop all the tr and td's from source table. Coz, my source table is going to be more than thousands rows and more than 50 cols."

I wouldn't worry about the size of the source table. Code to get the result you need first, and then optimise the code if the performance is poor. The code you showed is kind of implicitly looping through the original table twice anyway with td:nth-child(1) and then td:nth-child(2).



回答2:

You can use this:

$("#sourceT tr").each(function(index) {
    var newRow = $("<tr></tr>");
    $(this).find("td:lt(2)").each(function() {
        newRow.append($(this).clone());
    })
    $("#targetT").append(newRow);
});

Working demo: http://jsfiddle.net/jfriend00/JRwVN/

Or an even more compact version that uses more chaining instead of the .each():

$("#sourceT tr").each(function(index) {
    var newRow = $("<tr></tr>");
    $(this).find("td:lt(2)").clone().appendTo(newRow);
    $("#targetT").append(newRow);
});

Demo: http://jsfiddle.net/jfriend00/QRVfE/

Any code, regardless of selectors, that finds the columns you want is going to look in every row of the table. Walking the DOM (which is what these selector operations do) is not a slow operation. What is a slow operation is creating new DOM objects and inserting them in the DOM and there's no way to avoid that in your case.

If performance was super critical (something you should prove is actually a problem before attacking it), there are actually times when it's faster to create a giant HTML string and put that into the DOM all at once rather than inserting individual DOM objects.

If performance was critical, a version that constructs an HTML string seems to be about 20% faster in Chrome, IE10 and Firefox. It works like this:

var newTable = "";
$("#sourceT tr").each(function(index) {
    newTable += "<tr>";
    $(this).find("td:lt(2)").each(function() {
        newTable += "<td>" + this.innerHTML + "</td>";
    });
    newTable += "</tr>";
});
$("#targetT").html(newTable);

Demo: http://jsfiddle.net/jfriend00/MDAKe/

And, the jsperf that compares the last two ways: http://jsperf.com/table-copy

I'm sure there are other ways to improve performance (usually jQuery itself doesn't give you the fastest running code).


As it turns out, removing all jQuery makes it about 8-12x faster (depending upon browser):

var newTable = "";
var rows = document.getElementById("sourceT").rows;
for (var i = 0, len = rows.length; i < len; i++) {
    var cells = rows[i].cells;
    newTable += "<tr><td>" + cells[0].innerHTML + "</td><td>" + cells[1].innerHTML + "</td></tr>";
}
document.getElementById("targetT").innerHTML = newTable;

Demo: http://jsfiddle.net/jfriend00/7AJk2/



回答3:

Try

$('#sourceT tr').clone().appendTo('#targetT')
$('#targetT tr').find('td :gt(1)').remove();

Demo: Fiddle

OR

var clone = $('#sourceT tr').clone()
clone.find('td :gt(1)').remove();
clone.appendTo('#targetT')

Demo: Fiddle

I may prefer the OR portion since the dom is updated only once



回答4:

$('#sourceT tr')
        .clone()
        .find('td:gt(1)')
        .remove()
        .end()
        .appendTo('#targetT');

http://jsfiddle.net/C7dKF/



回答5:

I have goog way, how to play with columns, i write here full code:

function add_column(copy, paste)
{
		$("."+copy+":first").clone().appendTo("."+paste);
		$("."+paste+" tr:last input").val('');
		$("."+paste+" tr:last select").val('');
		// and etc...
}

function remove_column(e, paste)
{
		var how = $("."+paste+" tr").length;
		if(how >= 2)
		{
				$(e).parent().parent().remove();
		} else {
				$("."+paste+" input").val('');
				$("."+paste+" select").val('');
				// and etc...
		}
}
<div class="tab-pane fade" id="atostogos">
										<div class="panel-body">

											<form action="" method="post" autocomplete="off">
											<div class="table-responsive">
												<table class="table table-striped table-bordered">
													<thead>
														<tr>
															<th width="30%">Priežastis</th>
															<th width="15%">Data nuo</th>
															<th width="15%">Data iki</th>
															<th width="30%">Pastabos</th>
															<th width="10%">Veiksmai</th>
														</tr>
													</thead>
													<tbody class="paste_place">
															<tr class="copy_item">
																	<td><input type="text" name="priezastis[]" class="form-control" placeholder="Įveskite..."/></td>
																	<td><input type="text" name="data_nuo[]" class="form-control datepicker" placeholder="Įveskite..."/></td>
																	<td><input type="text" name="data_iki[]" class="form-control datepicker" placeholder="Įveskite..."/></td>
																	<td><input type="text" name="pastabos[]" class="form-control" placeholder="Įveskite..."/></td>
																	<td><a onclick="add_column('copy_item', 'paste_place');"><i style="font-size: 20px;" class="icon-plus-circle2"></i></a> &nbsp;<a onclick="remove_column(this, 'paste_place');"><i style="font-size: 20px; color: red;" class="icon-minus-circle2"></i></a></td>
															</tr>
													</tbody>
												</table>
										</div>

										<div class="row" style="margin-top: 20px;">
												<div class="col-md-12">
														<div class="text-right">
															<button name="holidays_info" type="submit" class="btn btn-primary">Išsaugoti <i class="icon-arrow-right14 position-right"></i></button>
														</div>
												</div>
										</div>
									</form>

										</div>
									</div>