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
Related
Hey i have this code:
<body>
<table>
<tr>
<td class="first">100</td>
</tr>
</table>
<h4 class=curs style="display:none">10</h4>
<script>
document.body.onload = function(){
var firstTdVal = document.getElementsByClassName('first')[0].innerHTML;
var secondTdVal = document.getElementsByClassName('curs')[0].innerHTML;
var valueToBeShown = parseInt(firstTdVal)/ parseInt(secondTdVal);
document.getElementsByClassName('first')[0].innerHTML = valueToBeShown ;
}
</script>
</body>
As you see ".first" has a number in it,this number is divied to ".curs" and the result is showed in ".first" too.Now the problem is that for exemple i add 100 more td's with class ".second,.third...,.hundred" in table.How to make script to do the same for all td's as it does for the ".first"(devide to ".curs").How do i do this in my JS by keeping it complex.
Use document.querySelectorAll to get an array of matched elements (matched with CSS selector), then loop through them using forEach, applying you logic one td at a time. Like this:
// querySelector gets the first element matched. textContent get the text of that element
var cursValue = parseInt(document.querySelector(".curs").textContent);
// querySelectorAll get an array of all the matched elements
var tds = document.querySelectorAll("td");
// loop through that array one td at a time
tds.forEach(function(td){
// get the text of the current td
var value = parseInt(td.textContent);
// if the value is not valid (a string for example) return and don't process anymore for this td (go straight to the next one).
if(isNaN(value)) return;
// calculate the new value
value = value / cursValue;
// change the text of this td (update it to the new value)
td.textContent = value;
});
NOTE: querySelector and querySelectorAll match elements using CSS selectors, so to match an element using a class the selector should be ".className", to match it using an ID: "#someID", ... All CSS selectors are accepted (even this one: "#anID>li.some-class a:not([href])").
NOTE2: tds is an array, so if you don't want to use forEach you can use a normal for loop (for(var i = 0; i < tds.length; i++) ...).
This will iterate over your table (be sure to set the table ID) (open dev console to view output but it's pretty straight forward.)
var table = document.getElementById("myTable");
for (var row of table.rows) {
for (var col of row.cells) {
console.log(col.className, col.innerHTML); //Class names and the values of the elements.
}
}
If you need anymore help please ask because I do not fully understand what you're trying to do here.
Here's a way where you put the number to be divided by in the first td, the number to divide by in the second td, and the result will be placed in the third td.
var trs = document.getElementsByTagName('tr');
for (var i = 0; i< trs.length; i++) {
var tds = trs[i].getElementsByTagName('td'),
first = tds[0].textContent,
second = tds[1].textContent,
third = tds[2],
result = (parseInt(first) / parseInt(second));
third.innerHTML = result;
}
<table>
<tr>
<td>10</td>
<td>2</td>
<td></td>
</tr>
<tr>
<td>4</td>
<td>2</td>
<td></td>
</tr>
</table>
i am trying to update first row width with JavaScript,
I have multiple tables
<table page="1">
<tbody>
<tr><td>aaaa</td><td>bbbbb</td></tr>
<tr><td>cccc</td><td>ddddd</td></tr>
....
</tbody>
</table>
<table page="2">
<tbody>
<tr><td>eeee</td><td>fffff</td></tr>
<tr><td>gggg</td><td>hhhhh</td></tr>
....
</tbody>
</table>
and an array
var cw = ["100","500"];
i am trying to create a function that will change only the tds from first row inside each table, so the end result should be
<table page="1">
<tbody>
<tr><td style="width:100px;">aaaa</td><td style="width:500px;">bbbbb</td></tr>
<tr><td>cccc</td><td>ddddd</td></tr>
....
</tbody>
</table>
<table page="2">
<tbody>
<tr><td style="width:100px;">eeee</td><td style="width:500px;">fffff</td></tr>
<tr><td>gggg</td><td>hhhhh</td></tr>
....
</tbody>
</table>
Since i only started using JavaScript i don't know best way to do things, yet, so i put this jsfiddle together from different examples, the problem is that i will have a lot of tables in one page (around 300) and i would like to know if this is the best way to do it:
var cw = ["100","500"];
var i,j,col;
var tables = document.getElementsByTagName("table");
for(i = 0;i<tables.length;i++) {
for ( j = 0, col; col = tables[i].rows[0].cells[j]; j++) {
col.style.width = cw[j]+'px';
}
}
i am afraid that 2 loops will make the browser unresponsive or slow, so can this be done safer with JavaScript or jquery?
Also i need this to work on IE, Chrome and Firefox
Thanks
Here is an example of how it should work
var size = ["100px", "500px"];
var tr = document.querySelectorAll('tbody tr:first-child');
for (i = 0; i < tr.length; i++) {
tr[i].firstElementChild.style.width = size[0];
tr[i].querySelector('td:nth-child(2)').style.width = size[1];
}
td {
background: yellow;
}
// Background for showing purpose only!
<table page="1">
<tbody>
<tr><td>aaaa</td><td>bbbbb</td></tr>
<tr><td>cccc</td><td>ddddd</td></tr>
</tbody>
</table>
<table page="2">
<tbody>
<tr><td>eeee</td><td>fffff</td></tr>
<tr><td>gggg</td><td>hhhhh</td></tr>
</tbody>
</table>
Enjoy!
I'm not sure you'll be able to get away from using two loops. One to go through each table and find the first row and the second to apply the widths to each td. Here's my jQuery version:
function assignWidths(arr){
$('table').each(function(){
var firstRowTds = $(this).find('tr').eq(0).children('td');
firstRowTds.each(function(i){
$(this).css('width', arr[i] + 'px');
});
});
}
I am using a JavaScript snippet to show a responsive table, setting the headers on mobile via attributes. This works, but, if I use a second table with the same class, it goes all wrong on mobile (please resize your screen to see this); the headers of.
What am I doing wrong here and how can I fix this?
This is the HTML:
<table class="test">
<thead>
<tr>
<th>Bla</th>
<th>Bla</th>
<th>Bla</th>
</tr>
</thead>
<tbody>
<tr>
<td>Bla</td>
<td>Blabla</td>
<td>Blablabla</td>
</tr>
</tbody>
</table>
<table class="test">
<thead>
<tr>
<th>Not</th>
<th>Not</th>
</tr>
</thead>
<tbody>
<tr>
<td>Twatwa</td>
<td>Twatwa</td>
</tr>
</tbody>
</table>
http://codepen.io/anon/pen/QbJqVv
Edit: after the new answer, it does show table headers on the second table now, but not the correct ones. It just puts the table headers of the first table, into the second.
As I wrote in the comments, you need to handle each table separately. For .querySelectorAll('.test th') will simply give you all th elements, irregardless of which table they belong to.
Here's a quick example of how this could be done.
// for each .test
[].forEach.call(document.querySelectorAll('.test'), function (table) {
// get header contents
var headers = [].map.call(table.querySelectorAll('th'), function (header) {
return header.textContent.replace(/\r?\n|\r/, '');
});
// for each row in tbody
[].forEach.call(table.querySelectorAll('tbody tr'), function (row) {
// for each cell
[].forEach.call(row.cells, function (cell, headerIndex) {
// apply the attribute
cell.setAttribute('data-th', headers[headerIndex]);
});
});
});
demo: http://codepen.io/anon/pen/NqEXqe
First of all, your HTML is invalid, as you are not closing any of your elements (<tr><td></td></tr> etc) - but that's another issue. Please practice good HTML standards.
You are not using querySelectorAll when selecting your table bodies, so you're only setting the attribute in the first one found.
This revised snippet should achieve what you are trying to do.
var headertext = [],
headers = document.querySelectorAll(".test th"),
tablerows = document.querySelectorAll(".test th"),
tablebody = document.querySelectorAll(".test tbody");
for(var i = 0; i < headers.length; i++) {
var current = headers[i];
headertext.push(current.textContent.replace(/\r?\n|\r/,""));
}
for (var tb = 0; tb < tablebody.length; tb++) {
for (var i = 0, row; row = tablebody[tb].rows[i]; i++) {
for (var j = 0, col; col = row.cells[j]; j++) {
col.setAttribute("data-th", headertext[j]);
}
}
}
I have the below table and I am using the below code to get the index of the tr with the id tbl1.The issue is that the index being returned which should be 2 is coming out correct in IE but it is coming as 3 in chrome and firefox.Can someone please tell me what I am doing wrong here.
var parent = document.getElementById("tbl1").parentElement;
var tr = document.getElementById("tbl1");
var index = -1;
for (var i = 0; i < parent.childNodes.length; i++) {
if (parent.childNodes.item(i) == tr) {
index = ++i;
break;
}
}
<TABLE border=0 cellSpacing=0 cellPadding=0><TBODY>
<TR>
</TR>
<TR id="tbl1">
</TR>
<TR></TR>
</TBODY></TABLE>
How about just use rowIndex:
var tr = document.getElementById("tbl1"),
index = tr.rowIndex + 1;
console.log(index); // => 2
See demo
I know you didn't ask for a solution using jQuery, anyway:
$('#tbl1').index()+1
gives you 2 as well.
It works for any kind of node, not only TR.
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;
}