I want to append a new row in my table using Javascript but the new row should be like my previous rows.
I am using CSS to format my rows.
If you are using jQuery it will be something like this:
$(document).ready(function() {
$("table tr:last").clone().appendTo("table");
})
Replacing table with the id or class of your table (unless you only plan to have one table).
Using good old Node.cloneNode(deep) along with HTMLTableElement.rows:
HTML:
<table id="foo">
<tbody id="bar">
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
</tbody>
</table>
JS:
var foo = document.getElementById("foo");
var bar = document.getElementById("bar");
var rows = foo.rows;
var lastRow = rows[rows.length-1];
var newRow = cloneRow(lastRow, true, bar);
function cloneRow(row, append, parent)
{
var newRow = row.cloneNode(true);
if(append)
{
if(parent)
{
parent.appendChild(newRow);
}
}
return newRow;
}
For comparison's sake, here's my code juxtaposed against the jQuery answer: http://jsperf.com/dom-methods-vs-jquery-with-tables
Let's say that your row has a css style of .row
So you could just use DOM methods to create a new tr, add the class="row" then add the appropriate amount of td
Here is a solution that avoids the use of the cloneNode method, and that do not copy the content, data or events of the previous last row, just its CSS attributes and class names.
The new row will have the same number of cell as the previous last row.
var lastRow = myTable.rows[myTable.rows.length-1];
var newRow = myTable.insertRow();
newRow.className = lastRow.className;
newRow.style.cssText = lastRow.style.cssText;
for (var i = 0; i < lastRow.cells.length; i++) {
var newCell = newRow.insertCell(i);
newCell.className = lastRow.cells[i].className;
newCell.style.cssText = lastRow.cells[i].style.cssText;
}
Related
I'm trying to use the insertcell method to add a column to my table but either I'm getting the syntax wrong or it isn't working. I wondered if anyone could explain where I am going wrong?
The table body in the html is populated dynamically with some other JavaScript but I don't think this is the problem as I've tested grabbing some content from that table with an alert box and it works (commented out below):
<!DOCTYPE html>
<script type="text/javascript" src="fullstationxyparser.js">
</script>
<html>
<body>
<table border=1>
<thead>
<tr>
<td>Element Name</td>
<td>x</td>
<td>y</td>
<td>testCol</td>
</tr>
</thead>
<tbody id="stationlist">
</tbody>
</table>
</body>
</html>
function addStationNames() {
var myTable = document.getElementById("stationlist");
var stationListRows = myTable.getElementsByTagName('tr');
for (var i = 1; i < stationListRows.length; i++) {
var cell = stationListRows[i].getElementsByTagName('td');
var stationName = cell[0].innerHTML; //get station id from element Name column
var currentRow = stationListRows[i];
var newCol = currentRow.insertcell(-1);
newCol.innerHTML = stationName;
//alert(stationName);
}
}
In Firefox developer tools, I get TypeError: "currentRow.insertcell is not a function". Perhaps I can't use the insertcell method on a row collection?
In general you can call the insertRow() method on a Table DOM element, followed by calls to the insertCell() method as shown below to dynamically add <td> tags to your table with JavaScript.
Be careful to call insertCell() (with capital C) rather than insertcell() as you are currently doing:
const table = document.querySelector('table');
/* Insert new row */
const row = table.insertRow();
/* Insert cells (td) for row */
const td0 = row.insertCell(0);
const td1 = row.insertCell(1);
const td2 = row.insertCell(2);
const td3 = row.insertCell(3);
/* Populate cells with data */
td0.innerText = 'Foo';
td1.innerText = '3';
td2.innerText = '6';
td3.innerText = 'success';
<table border="1">
<thead>
<tr>
<td>Element Name</td>
<td>x</td>
<td>y</td>
<td>testCol</td>
</tr>
</thead>
<tbody>
</tbody>
</table>
Specific to your code, some other changes to consider might be as listed in this code snippet:
function addStationNames() {
/* Condense table row access into single query */
const stationRows = document.querySelectorAll("#stationlist tr");
stationRows.forEach((stationRow, i) => {
/* Skip first row */
if(i === 0) { return; }
/* Get station name from text of first cell */
const stationName = stationRow.querySelector('td:first-child').innerText;
/* Insert last cell on row and assign station name */
stationRow.insertCell(-1).innerText = stationName;
});
/*
Old code:
for (let i = 1; i < stationListRows.length; i++) {
var cell = stationListRows[i].getElementsByTagName('td');
var stationName = cell[0].innerHTML;
var currentRow = stationListRows[i];
var newCol = currentRow.insertcell(-1);
newCol.innerHTML = stationName;
}
*/
}
addStationNames();
<!-- set table id to stationlist -->
<table border="1" id="stationlist">
<thead>
<tr>
<td>Element Name</td>
<td>x</td>
<td>y</td>
<td>testCol</td>
</tr>
<tr>
<td>90's pop</td>
<td>232</td>
<td>543</td>
</tr>
</thead>
<tbody>
<!-- Remove id from tbody -->
</tbody>
</table>
An alternative to the answer above (which is totally fine) is this method, which is also a more general method of creating any html element:
const table = document.getElementById('one');
const newRow = document.createElement("tr");
let newCell = document.createElement("td");
newCell.textContent = "first cell";
let newCell2 = document.createElement("td");
newCell2.textContent = "second cell";
newRow.appendChild(newCell);
newRow.appendChild(newCell2);
table.appendChild(newRow);
https://jsfiddle.net/zgaosdbv/
I have a table element defined below as $table. I am trying to run a function on every cell a specific column that is defined by a specific table heading - qc_statusTh. I have found the index of that table heading (qc_statusColumnIndex) and have been able to grab the next table cell in that column - qc_statusCell.
However, I am not able to loop through the table cells and run a function on each table cell in that column.
Here is the JavaScript code I have so far:
$(document).ready(function() {
var $table = $("table.tables.list");
if ($table.length > 0) {
var qc_statusTh = $("th.headersub:contains('qc_status')");
var qc_statusColumnIndex = $(qc_statusTh).index();
var qc_statusCell = $($table).find("td").eq(qc_statusColumnIndex);
// this does not work. this only replaces the first cell
// in the row after qc_statusTh with "TESTING"
$(qc_statusCell).each(function() {
$(this).replaceWith("TESTING");
});
}
});
How can I edit this code to loop through each cell in the table that has an equal index to qc_statusColumnIndex?
If you think about it, you really want to iterate (using each) over the rows of the table, not the cells. If you do that, you can then grab the nth td element from each row and apply your transformation.
$(document).ready(function() {
var $table = $("table.tables.list");
if ($table.length > 0) {
var qc_statusTh = $("th.headersub:contains('qc_status')");
var qc_statusColumnIndex = $(qc_statusTh).index();
var qc_rows = $($table).find('tr');
$(qc_rows).each(function() {
$(this).find('td').eq(qc_statusColumnIndex).replaceWith("TESTING");
});
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table class="tables list">
<thead>
<th class="headersub">qc_example</th>
<th class="headersub">qc_status</th>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Ok</td>
</tr>
<tr>
<td>2</td>
<td>Ok</td>
</tr>
<tr>
<td>3</td>
<td>Error</td>
</tr>
</tbody>
</table>
With JavaScript, how can I add a new row to an HTML table that sums the values following the 2nd row.
Here's an example of what the above depicts:
Expected outcome:
Here is the html markup:
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
<!DOCTYPE html>
<html>
<body>
<table border="1" style="width:100%">
<tr>
<td>Branch</td>
<td>Division</td>
<td>TallyA</td>
<td>TallyB</td>
<td>TallyC</td>
</tr>
<tr>
<td>Alpha</td>
<td>A101</td>
<td>6</td>
<td>4</td>
<td>5</td>
</tr>
<tr>
<td>Bravo</td>
<td>B102</td>
<td>16</td>
<td>8</td>
<td>10</td>
</tr>
<tr>
<td>Charlie</td>
<td>C103</td>
<td>11</td>
<td>17</td>
<td>21</td>
</tr>
</table>
</body>
</html>
</body>
</html>
Here is my solution. It may look verbose, but that's necessary with the complexity of this task.
First, I referenced the button and table elements. To prevent repeated clicks that will add more rows, and destroy the code, I created a boolean variable that checks whether the rows have already been summed. The code only runs the first time inside the if(!summedItems) conditional.
I then created new td elements for all five columns in the table and created text nodes for all but the division one.
I then created selectors and this is where it got tricky. The first row does not contain numerical value, so I had to query all rows from the second further. I did that with tr:nth-child(n+2).
I then need to find the third cell in each of these rows. The descendant or child selectors can be used for this. The full selector is tr:nth-child(n+2) td:nth-child(3). Repeat that for the next two, only increment the values inside td:nth-child.
Since we need to iterate through all these values, I created three separate arrays to store the values inside the third, fourth and fifth columns respectively. It's important to note that these values are of type string and they need to be converted to integers. To do that simply add a + sign before the string. Iterating over the number of elements in each query, I populated the arrays.
Now we need to add up all of these items, and we can do that with the reduce method.
Now add the textnodes to the cells, the cells to the row and finally the row to the table. Finally, set the summedItems variable to true to prevent crazy behavior.
var button = document.getElementById("total-items");
var table = document.getElementById("my-table");
var summedItems = false;
function sumItems() {
if (!summedItems) {
var row = document.createElement("tr");
var branch = document.createElement("td");
var division = document.createElement("td");
var tallyA = document.createElement("td");
var tallyB = document.createElement("td");
var tallyC = document.createElement("td");
var branchText = document.createTextNode("Total");
var sumA = document.querySelectorAll("tr:nth-child(n+2) td:nth-child(3)");
var sumB = document.querySelectorAll("tr:nth-child(n+2) td:nth-child(4)");
var sumC = document.querySelectorAll("tr:nth-child(n+2) td:nth-child(5)");
var aSums = [], bSums = [], cSums = [];
for (var i = 0; i < sumA.length; i++) {
aSums.push(+(sumA[i].innerHTML));
}
for (var i = 0; i < sumB.length; i++) {
bSums.push(+(sumB[i].innerHTML));
}
for (var i = 0; i < sumC.length; i++) {
cSums.push(+(sumC[i].innerHTML));
}
aSums = aSums.reduce((a,b) => a + b)
bSums = bSums.reduce((a,b) => a + b)
cSums = cSums.reduce((a,b) => a + b)
var tallyAText = document.createTextNode(aSums);
var tallyBText = document.createTextNode(bSums);
var tallyCText = document.createTextNode(cSums);
branch.appendChild(branchText);
tallyA.appendChild(tallyAText);
tallyB.appendChild(tallyBText);
tallyC.appendChild(tallyCText);
[branch, division, tallyA, tallyB, tallyC].forEach((e) => row.appendChild(e)
)
table.appendChild(row);
summedItems = true;
}
}
button.addEventListener("click", function() {
sumItems();
});
<table id="my-table" border="1" style="width:100%">
<tr>
<td>Branch</td>
<td>Division</td>
<td>TallyA</td>
<td>TallyB</td>
<td>TallyC</td>
</tr>
<tr>
<td>Alpha</td>
<td>A101</td>
<td>6</td>
<td>4</td>
<td>5</td>
</tr>
<tr>
<td>Bravo</td>
<td>B102</td>
<td>16</td>
<td>8</td>
<td>10</td>
</tr>
<tr>
<td>Charlie</td>
<td>C103</td>
<td>11</td>
<td>17</td>
<td>21</td>
</tr>
</table>
<button id="total-items">Total Items</button>
with jQuery:
$("table").each(function() {
var $table = $(this);
$row = $("<tr>")
$row.append("<td>Totale</td>")
var sums = [];
$table.find("tr").each(function(){
var index = 0;
$(this).find("td").each(function() {
if (!sums[index]) sums[index] = 0;
sums[index] += parseInt($(this).html());
index++;
})
})
for(var i=1;i<sums.length;i++) {
var el = sums[i];
if (isNaN(el)) el = "";
$row.append("<td>"+el+"</td>")
}
$table.append($row)
})
jsFiddle
Here I have an existing table:
<table>
<tr>
<td>content
</td>
</tr>
</table>
and in JavaScript, I have already obtained this table:
var isert = main_code.getElementsByTagName("table");
How to use JavaScript to attach tags to this table so it looks like:
<div id=extra>
<table>
<tr>
<td>content
</td>
</tr>
</table>
</div>
PS: It seems that insertAdjacentHTML only works on current <table>tag, not entire <table></table>.
Thank!
Try this:
var tables = main_code.getElementsByTagName("table");
for(var i = 0; i < tables.length; i++) {
var div = document.createElement("div");
var _t = tables[i];
var parent = _t.parentNode;
div.id = "extra";
parent.replaceChild(div, _t);
div.appendChild(_t);
}
Although, this adds the same id to multiple div container, if there are more than one table. You might want to use div.className = 'extra' instead.
I have a table that is a history of a mysql record.
I want to add a button that will highlight the changes.
<table>
<tr>
<td>100</td>
<td>200</td>
<td>300</td>
</tr>
<tr>
<td>100</td>
<td>200</td>
<td>600</td>
</tr>
</table>
In this example the 600 would be highlighted as it was 300 and is now 600.
UPDATE: Thanks, I should have said there would be more than 2 rows. could be upto 20 rows
This jsFiddle shows an example that will iterate over a table of any size and highlight the cells that have changed from the previous row.
$(function() {
var $rows = $("tr");
for (oldIndex = 0; oldIndex < $rows.length-1; oldIndex++) {
var newIndex = oldIndex + 1;
var $oldCols = $("td", $rows[oldIndex]);
var $newCols = $("td", $rows[newIndex]);
for (col = 0; col < $oldCols.length; col++) {
var $newCol = $($newCols[col]);
if ($($oldCols[col]).html() != $newCol.html()) {
$newCol.addClass("highlight");
}
}
}
});
Your solution should go along these lines. Assuming set1 and set2 are id's of two trs here is a sample code (not tested).
var s1 = $('tr#set1 td');
var s2 = $('tr#set2 td');
var l = $('tr#set1 td').length;
for(var i =0; i<l i++){
if(s1.eq(i).text() != s2.eq(i)){
$(s2.eq(i)).highlight();
}
}
$('table tr.new td').each(function(i){
//First TR td, Previous Rows
td = $(this);
check = $('table tr.prev td:eq('+i+')');
if(td[0].innerText != check[0].innerText)
{
check.addClass('Changed');
}
})
This should do it but you need to add 2 classes:
<table>
<tr class="new">
<td>150</td>
<td>200</td>
<td>300</td>
</tr>
<tr class="prev">
<td>100</td>
<td>200</td>
<td>600</td>
</tr>
</table>
Demo: http://jsfiddle.net/hjXZd/1/
Hope this helps.
I advise you to do an attr for each TD and place the mysql id in there so that you will only compare the rows that are the same in the DB, otherwise if your first list has more items then the second list the results will be corrupt.
Assuming your table has the id results, here is a solution:
var topRow = $('table#results tr:eq(0)');
var bottomRow = $('table#results tr:eq(1)');
topRow.find('td').each(function(index,item){
var shadow = bottomRow.find('td:eq('+index+')');
if($(item).contents().text()!=shadow.contents().text()){
shadow.css({'background':'yellow'});
}
});
Update: this solution compares the top row with all following ones:
$('table#results tr:eq(0) td').each(function(index,item){
var orig = $(item).contents().text();
$('table#results tr:gt(0)').find('td:eq('+index+')').each(function(index2,item2){
var shadow = $(item2);
if(orig!=shadow.contents().text()){
shadow.css({'background':'yellow'});
}
});
});
Using Jquery .live you can handle multiple elements.
See here
http://api.jquery.com/live/
You have to give ids for the changed values.. which can be inside divs.
Hope td also may work
On button click using this .live you can chnage style of div
like highlighting.
Use addClass function os jquery itslef or you can add css using jquery add