JS - Compare first row to other rows in table - javascript

I'm a completely newbie and looking for help.
Given the following table:
<table id="table">
<thead>
# FIRST ROW
<tr>
<th>Apple</th>
<th>Pizza</th>
<th>Eggs</th>
</tr>
<tbody>
# SECOND ROW
<tr>
<td>Apple</td> --> should end with 'success' class
<td>Juice</td>
<td>Lettuce</td>
<td>Oranges</td>
<td>Eggs</td> --> should end with 'success' class
</tr>
# THIRD ROW
<tr>
<td>Pizza</td> --> should end with 'success' class
<td>Chicken</td>
</tr>
</tbody>
</table>
I would like to add class 'success' to every td in SECOND and THIRD rows whenever it matches any td in FIRST row (and only in FIRST ROW).
For now I came up with adding <td> values of first row to array and I'm not sure what steps should I take next (filter? for loop and '===' comparison?):
function myFunction() {
var tHeadersValues = [];
var tHeaders = document.getElementById("table").rows[0].cells;
for (var i = 0; i < tHeaders.length; i++) {
tHeadersValues.push(tHeaders[i].textContent);
}
return tHeadersValues;
}

Object.keys(tHeaders).map(key => tHeaders[key].textContent) transforms the td objects to an array with the containing text. The rest is straight forward:
function toValues(tHeaders) {
return Object.keys(tHeaders).map(function(key){
return tHeaders[key].textContent;
});
}
function myFunction() {
var rows = document.getElementById("results-table").rows;
var tHeadersValues = toValues(rows[0].cells);
for (var i = 1; i < rows.length; i++) {
var rowCells = rows[i].cells;
var values = toValues(rowCells);
for(var j=0;j<values.length;j++) {
if(values[j].length > 0 && tHeadersValues.indexOf(values[j]) > -1) {
rowCells[j].className = "success";
}
}
}
}
myFunction();
<style>
.success {
background-color: green;
}
</style>
<table id="results-table">
<thead>
<tr>
<th>Apple</th>
<th>Pizza</th>
<th>Eggs</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>Apple</td>
<td>Juice</td>
<td>Lettuce</td>
<td>Oranges</td>
<td>Eggs</td>
</tr>
<tr>
<td>Pizza</td>
<td>Chicken</td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>

function myFunc(){
var tds = document.getElementsByTagName("td");
var hds = document.getElementsByTagName("th");
for(var i=0; i<tds.length; i++) {
var tdContent = tds[i].innerHTML;
if(tdContent.length > 0){
for(var j = 0; j<hds.length; j++) {
if(tdContent === hds[j].innerHTML) {
document.getElementsByTagName("td")[i].className = "success";
}
}
}
}
}
myFunc();
<style>
.success {
background-color: green;
}
</style>
<table id="results-table">
<thead>
<tr>
<th>Apple</th>
<th>Pizza</th>
<th>Eggs</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>Apple</td>
<td>Juice</td>
<td>Lettuce</td>
<td>Oranges</td>
<td>Eggs</td>
</tr>
<tr>
<td>Pizza</td>
<td>Chicken</td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>

Related

Javascript Filtering by multiple columns

Borrowing code from the post below I am able to filter on 2 columns using the || (Or) operator.
However, I'd like to be able to filter using the && (And) operator.
I have been unsuccessful in my multiple attempts. I could use some help.
Filtering table multiple columns
function myFunction() {
var input0, input1, filter0, filter1, table, tr, td, cell, i, j;
document.getElementById("myInput0").value = 'Female';
document.getElementById("myInput1").value = 'Engineering';
input0 = document.getElementById("myInput0");
input1 = document.getElementById("myInput1");
filter0 = input0.value.toUpperCase();
filter1 = input1.value.toUpperCase();
table = document.getElementById("myTable");
tr = table.getElementsByTagName("tr");
for (i = 1; i < tr.length; i++) {
// Hide the row initially.
tr[i].style.display = "none";
td = tr[i].getElementsByTagName("td");
for (var j = 0; j < td.length; j++) {
cell = tr[i].getElementsByTagName("td")[j];
if (cell) {
if (cell.textContent.toUpperCase().indexOf(filter0)>-1 ||
cell.textContent.toUpperCase().indexOf(filter1)>-1) {
tr[i].style.display = "";
break;
}
}
}
}
}
<body>
<input type="text" id="myInput0">
<input type="text" id="myInput1">
<input type='button' onclick='myFunction()' value='click me' />
<table id="myTable">
<thead>
<tr>
<th>Firstname</th>
<th>Lastname</th>
<th>Gender</th>
<th>Department</th>
</tr>
</thead>
<tbody>
<tr>
<td>John</td>
<td>Doe</td>
<td>Male</td>
<td>Sales</td>
</tr>
<tr>
<td>Mary</td>
<td>Moe</td>
<td>Female</td>
<td>Service</td>
</tr>
<tr>
<td>July</td>
<td>Dooley</td>
<td>Female</td>
<td>Service</td>
</tr>
<tr>
<td>Anja</td>
<td>Ravendale</td>
<td>Female</td>
<td>Engineering</td>
</tr>
<tr>
<td>Thomas</td>
<td>Dubois</td>
<td>Male</td>
<td>Sales</td>
</tr>
<tr>
<td>Deidre</td>
<td>Masters</td>
<td>Female</td>
<td>Sales</td>
</tr>
<tr>
<td>Sean</td>
<td>Franken</td>
<td>Male</td>
<td>Engineering</td>
</tr>
</tbody>
</table>
</body>
For each cell, you can check each filter separately, then only change the DOM for rows where all filter conditions are met.
(This example uses a restructured version of your code.)
document.getElementById("myInput0").value = 'Female';
document.getElementById("myInput1").value = 'Engineering';
const
input0 = document.getElementById("myInput0"),
input1 = document.getElementById("myInput1"),
table = document.getElementById("myTable"),
rows = table.getElementsByTagName("tr");
function myFunction() {
filter0 = input0.value.toUpperCase(),
filter1 = input1.value.toUpperCase();
for (let row of rows) {
row.classList.add("hidden");
const cells = row.getElementsByTagName("td");
let
filter0met = false,
filter1met = false;
for (let cell of cells) {
if (cell.textContent.toUpperCase().includes(filter0)) {
filter0met = true;
}
if (cell.textContent.toUpperCase().includes(filter1)) {
filter1met = true;
}
}
if (filter0met && filter1met) {
row.classList.remove("hidden");
}
}
}
.hidden {
display: none;
}
<body>
<input type="text" id="myInput0"><input type="text" id="myInput1"><input type='button' onclick='myFunction()' value='click me' />
<table id="myTable">
<thead>
<tr>
<th>Firstname</th>
<th>Lastname</th>
<th>Gender</th>
<th>Department</th>
</tr>
</thead>
<tbody>
<tr>
<td>John</td>
<td>Doe</td>
<td>Male</td>
<td>Sales</td>
</tr>
<tr>
<td>Mary</td>
<td>Moe</td>
<td>Female</td>
<td>Service</td>
</tr>
<tr>
<td>July</td>
<td>Dooley</td>
<td>Female</td>
<td>Service</td>
</tr>
<tr>
<td>Anja</td>
<td>Ravendale</td>
<td>Female</td>
<td>Engineering</td>
</tr>
<tr>
<td>Thomas</td>
<td>Dubois</td>
<td>Male</td>
<td>Sales</td>
</tr>
<tr>
<td>Deidre</td>
<td>Masters</td>
<td>Female</td>
<td>Sales</td>
</tr>
<tr>
<td>Sean</td>
<td>Franken</td>
<td>Male</td>
<td>Engineering</td>
</tr>
</tbody>
</table>
</body>
After much trial and error for I was able to put together some JQuery that will dynamically search the first input, and then search those results for the second input. Note, I am using SP2016. While I've included it here in my post, I could not get the call to "https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js" to work. I found downloading and storing the file on my SharePoint site worked. For my requirement I wanted to display my list with grouped rows so I'm using a function to collapse the groups on load. The caveat is the groups in listview have to be configured as expanded.
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!DOCTYPE html>
<html>
<head>
<SCRIPT type="text/javascript"src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></SCRIPT>
<script>
//If rows are not grouped, remove this function
$(window).load(function () {
$(".ms-commentcollapse-icon").click();
});
$(document).ready(function() {
$("#myInput").on("keyup", function() {
var value = this.value.toLowerCase();
//If rows are not grouped, remove this line
$(".ms-commentexpand-icon").click();
$('.ms-listviewtable > tbody > tr').addClass('myInputMismatch').filter(function() {
return this.innerHTML.toLowerCase().indexOf(value) > -1;
}).removeClass('myInputMismatch');
});
$("#myInput1").on("keyup", function() {
var value = this.value.toLowerCase();
$('.ms-listviewtable > tbody > tr').addClass('myInput1Mismatch').filter(function() {
return this.innerHTML.toLowerCase().indexOf(value) > -1;
}).removeClass('myInput1Mismatch');
});
});
</script>
<style>
.myInputMismatch, .myInput1Mismatch { display: none; }
</style></head>
<input id="myInput" type="text" Placeholder="Search here 1st..."><input id="myInput1" type="text" Placeholder="Search here 2nd...">

loop over table to set the background css

My HTML table has some classes and table tag is used
Want to retain the classes as is, but all my table and tr , th or td are using td bgcolor which is an old technique.
I want to loop over the table and find if that bgcolor is defined, use the same color and convert it to a css based background color so i can print it in IE
function setBackground() {
var table = document.getElementById("table1");
//i found this in a previous stack overflow answer and tried it
for (var i = 0, row; row = table.rows[i]; i++) {
for (var j = 0, col; col = row.cells[j]; j++) {
//this is for debugging purposes... I can't even get this to work
alert(table.rows[i].cells[j]);
table.rows[i].cells[j].style.background = "orange"; //just an example
}
}
}
because IE is not able to print the background lines and colors for some reason using the webkit property
I cleaned up the for loops a little. You can read the attribute with getAttribute and set the style.
var table = document.getElementById("table1");
for (var i = 0; i < table.rows.length; i++) {
var row = table.rows[i]
for (var j = 0; j < row.cells.length; j++) {
var cell = row.cells[j]
var bgc = cell.getAttribute('bgcolor')
if (bgc) {
cell.style.background = bgc
}
}
}
td {
width: 30px; height: 30px;
}
<table id="table1">
<tr>
<td bgcolor="red"></td>
<td></td>
<td bgcolor="blue"></td>
</tr>
<tr>
<td></td>
<td bgcolor="green"></td>
<td></td>
</tr>
<tr>
<td bgcolor="yellow"></td>
<td></td>
<td></td>
</tr>
<tr>
<td bgcolor="silver"></td>
<td></td>
<td></td>
</tr>
</table>
You can just do it with one loop with getElementsByTagName
var tds = document.getElementById("table1").getElementsByTagName("td");
for (var i = 0; i < tds.length; i++) {
var cell = tds[i]
var bgc = cell.getAttribute('bgcolor')
if (bgc) {
cell.style.background = bgc
}
}
td {
width: 30px; height: 30px;
}
<table id="table1">
<tr>
<td bgcolor="red"></td>
<td></td>
<td bgcolor="blue"></td>
</tr>
<tr>
<td></td>
<td bgcolor="green"></td>
<td></td>
</tr>
<tr>
<td bgcolor="yellow"></td>
<td></td>
<td></td>
</tr>
<tr>
<td bgcolor="silver"></td>
<td></td>
<td></td>
</tr>
</table>
Get the color if found and then do with it whatever needed...
function setBackgroundColor(colorValue) {
const table = document.getElementById("table1");
const rows = table.children[0].rows
for (let i = 0; i < rows.length; i++) {
const tds = rows[i].children;
for (let j = 0; j < tds.length; j++) {
if (tds[j].bgColor === colorValue) {
console.log('Color found, do action')
}
}
}
}
setBackgroundColor('red')
<table id="table1">
<tr>
<th>Month</th>
<th>Savings</th>
</tr>
<tr>
<td bgcolor="red">January</td>
<td bgcolor="green">$100</td>
</tr>
</table>
You can do this:
var cells = $("#targetTable td");
for(i in cells){
color = $(cells[i]).attr('bgcolor');
console.log(color);
$(cells[i]).css({background: color});
}
as Taplar mentioned in the comment :
Use document.querySelectorAll('td[bgcolor]') to get the td that have bgcolor, loop through them and set the background to that color :
document.querySelectorAll('td[bgcolor]').forEach(e => {
const bgColor = e.getAttribute('bgcolor');
e.removeAttribute('bgcolor'); // optional, if you want to remove the attribute
e.style.background = bgColor;
})
<table id="table1">
<thead>
<th>A</th>
<th>B</th>
<th>C</th>
</thead>
<tbody>
<tr>
<td bgcolor="red">1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>4</td>
<td bgcolor="green">5</td>
<td>6</td>
</tr>
<tr>
<td>7</td>
<td>8</td>
<td bgcolor="blue">9</td>
</tr>
</tbody>
</table>

Adding rows to table body dynamically

I am trying to add rows to an existing table that has header and footer also.
Here is my code:
<script>
function test() {
var tbl = document.getElementById("tbl");
var lastRow = tbl.rows.length - 1;
var cols = tbl.rows[lastRow].cells.length;
var row = tbl.insertRow(-1);
for (var i = 0; i < cols; i++) {
row.insertCell();
}
}
</script>
<table id="tbl" onclick="test()">
<thead>
<tr>
<th>Month</th>
<th>Savings</th>
</tr>
</thead>
<tfoot>
<tr>
<td>Sum</td>
<td>$180</td>
</tr>
</tfoot>
<tbody>
<tr>
<td>January</td>
<td>$100</td>
</tr>
<tr>
<td>February</td>
<td>$80</td>
</tr>
</tbody>
</table>
when I click on any table I want to add new row to table body, but the issue here is the new row is added to table footer. please help me how to fix this issue.
You insert the row into the tBody element. Since there can be more than one tBody, you should refer to the tBodies prop of table at index 0.
var row = tbl.tBodies[0].insertRow(-1);
function test() {
var tbl = document.getElementById("tbl");
var lastRow = tbl.rows.length - 1;
var cols = tbl.rows[lastRow].cells.length;
var row = tbl.tBodies[0].insertRow(-1);
for (var i = 0; i < cols; i++) {
row.insertCell().appendChild(document.createTextNode(i));
}
}
test();
<table id="tbl" onclick="test()">
<thead>
<tr>
<th>Month</th>
<th>Savings</th>
</tr>
</thead>
<tfoot>
<tr>
<td>Sum</td>
<td>$180</td>
</tr>
</tfoot>
<tbody>
<tr>
<td>January</td>
<td>$100</td>
</tr>
<tr>
<td>February</td>
<td>$80</td>
</tr>
</tbody>
</table>
Try something like this. Just clone first row and then append it as child to your table. Hope it will help you
function appendRow() {
let tbl = document.getElementById("tbl");
let newRow = tbl.rows[0].cloneNode(true);
tbl.appendChild(newRow);

HTML Table onClick function to get table row key and value

I wanted to create a HTML table with onclick function to get the key and value of a row, so far the onclick function is working but it displaying and empty array for me, how can I fix this problem. Thanks.
I wanted it to be display in console log in this format when you click on the first row:
{ "name":"Clark", "age":29};
Here is my code
var table = document.getElementById("tableID");
if (table != null) {
for (var i = 0; i < table.rows.length; i++) {
table.rows[i].onclick = function() {
tableText(this);
};
}
}
function tableText(tableRow) {
var myJSON = JSON.stringify(tableRow);
console.log(myJSON);
}
<table align="center" id="tableID" border="1" style="cursor: pointer;">
<thead>
<tr>
<th hidden="hidden"></th>
<th>name</th>
<th>age</th>
</tr>
</thead>
<tbody>
<tr>
<td >Clark</td>
<td>29</td>
</tr>
<tr>
<td >Bruce</td>
<td>30</td>
</tr>
</tbody>
</table>
I edited my answer to return the data as an object. Run the script and have a look.
var table = document.getElementById("tableID");
if (table) {
for (var i = 0; i < table.rows.length; i++) {
table.rows[i].onclick = function() {
tableText(this);
};
}
}
function tableText(tableRow) {
var name = tableRow.childNodes[1].innerHTML;
var age = tableRow.childNodes[3].innerHTML;
var obj = {'name': name, 'age': age};
console.log(obj);
}
<table align="center" id="tableID" border="1" style="cursor: pointer;">
<thead>
<tr>
<th hidden="hidden"></th>
<th>name</th>
<th>age</th>
</tr>
</thead>
<tbody>
<tr>
<td >Clark</td>
<td>29</td>
</tr>
<tr>
<td >Bruce</td>
<td>30</td>
</tr>
</tbody>
</table>
I think you can use tr.innerTestto get the value in the tags
If you are using jQuery you can add an eventlistener to the table like this
$('#tableID').on('click', 'tr', function(e){
tableText($(this).html());
});
function tableText(tableRow) {
var myJSON = JSON.stringify(tableRow);
console.log(myJSON);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js"></script>
<table align="center" id="tableID" border="1" style="cursor: pointer;">
<tr>
<td>Text</td>
<td>MoreText</td>
<td>Lorem</td>
<td>Ipsum</td>
</tr>
<tr>
<td>Text</td>
<td>MoreText</td>
<td>Lorem</td>
<td>Ipsum</td>
</tr>
<tr>
<td>Text</td>
<td>MoreText</td>
<td>Lorem</td>
<td>Ipsum</td>
</tr>
<tr>
<td>Text</td>
<td>MoreText</td>
<td>Lorem</td>
<td>Ipsum</td>
</tr>
</table>
There are many ways to do what you're after, however a robust and extensible way would be to get the property names from the table header row, then get the values from the row that was clicked on.
I don't know why you have hidden cells in the header, it just complicates things. If you're using it for data, that would be much better in an associated object or data-* property of the table or row.
function getRowDetails(event) {
row = this;
var table = row.parentNode.parentNode;
var header = table.rows[0];
// Get property names from header cells
var props = [].reduce.call(header.cells, function(acc, cell ) {
if (!cell.hasAttribute('hidden')) {
acc.push(cell.textContent);
}
return acc;
}, []);
// Get value for each prop from data cell clicked on
var result = props.reduce(function(acc, prop, i) {
acc[prop] = row.cells[i].textContent;
return acc;
}, {});
// Do something with result
console.log(result);
return result;
}
// Add listener to body rows, could also put single listener on table
// and use event.target to find row
window.onload = function() {
[].forEach.call(document.getElementsByTagName('tr'), function(row, i) {
if (i) row.addEventListener('click', getRowDetails, false);
});
}
<table align="center" id="tableID" border="1">
<thead>
<tr><th hidden="hidden"></th><th>name</th><th>age</th></tr>
</thead>
<tbody style="cursor: pointer;">
<tr><td >Clark</td><td>29</td></tr>
<tr><td >Bruce</td><td>30</td></tr>
</tbody>
</table>

Sorting pairs of rows with tablesorter

http://jsfiddle.net/9sKwJ/66/
tr.spacer { height: 40px; }
$.tablesorter.addWidget({
id: 'spacer',
format: function(table) {
var c = table.config,
$t = $(table),
$r = $t.find('tbody').find('tr'),
i, l, last, col, rows, spacers = [];
if (c.sortList && c.sortList[0]) {
$t.find('tr.spacer').removeClass('spacer');
col = c.sortList[0][0]; // first sorted column
rows = table.config.cache.normalized;
last = rows[0][col]; // text from first row
l = rows.length;
for (i=0; i < l; i++) {
// if text from row doesn't match last row,
// save it to add a spacer
if (rows[i][col] !== last) {
spacers.push(i-1);
last = rows[i][col];
}
}
// add spacer class to the appropriate rows
for (i=0; i<spacers.length; i++){
$r.eq(spacers[i]).addClass('spacer');
}
}
}
});
$('table').tablesorter({
widgets : ['spacer']
});
<table id="test">
<thead>
<tr>
<th>Name</th>
<th>Number</th>
<th>Another Example</th>
</tr>
</thead>
<tbody>
<tr>
<td>Test4</td>
<td>4</td>
<td>Hello4</td>
</tr>
<tr>
<td colspan="3">Test4</td>
</tr>
<tr>
<td>Test3</td>
<td>3</td>
<td>Hello3</td>
</tr>
<tr>
<td colspan="3">Test3</td>
</tr>
<tr>
<td>Test2</td>
<td>2</td>
<td>Hello2</td>
</tr>
<tr>
<td colspan="3">Test2</td>
</tr>
<tr>
<td>Test1</td>
<td>1</td>
<td>Hello1</td>
</tr>
<tr>
<td colspan="3">Test1</td>
</tr>
</tbody>
</table>
This sorts just the way I want it if you sort it by the first column, but the other two columns don't maintain the same paired 'tr' sort im looking for.
Any help on this?
Use the expand-child class name on each duplicated row:
<tr>
<td>Test3</td>
<td>3</td>
<td>Hello3</td>
</tr>
<tr class="expand-child">
<td colspan="3">Test3</td>
</tr>
It's defined by the cssChildRow option:
$('table').tablesorter({
cssChildRow: "expand-child"
});​
Here is a demo of it in action.

Categories

Resources