I'm working on a page with large multiple tables in Html.
To filter them I found and adapted this script that filter for every cell of the table:
<script>
function searchtable() {
var input, filter, table, tr, td, i;
input = document.getElementById("myInput");
filter = input.value.toUpperCase();
table = document.getElementById("myTable");
tr = table.getElementsByTagName("tr");
th = table.getElementsByTagName("th");
for (i = 1; i < tr.length; i++) {
if (!tr[i].classList.contains('header')) {
td = tr[i].getElementsByTagName("td"),
match = false;
for (j = 0; j < td.length; j++) {
if (td[j].innerHTML.toUpperCase().indexOf(filter) > -1) {
match = true;
break;
}
}
if (!match) {
tr[i].style.display = "none";
} else {
tr[i].style.display = "";
}
}
}
}
</script>
The problem here is that the code work only in the first table of the page and not in the others.
I'd prefer to NOT repeat the script personalizing for every and each table.
Do you have any suggestion on how to personalize the script to look up in multiple tables?
Edit:
Do you know any different script that do the same thing?
I've tried to explain most parts I've changed. In the end the code itsself is a bit shorter, but a tiny bit more complicated. If I made assumptions that aren't correct, let me know. (For example, I'm assuming the 'header' class is only atatched to <tr> elements inside the <thead> who contains <th> elements)
var searchTable = function searchTable(table, input) {
// Since we bound the input, we can use input.value to get the current words typed into the input.
var filter = input.value,
// A table has both a thead and a tbody.
// By only selecting the tr nodes from the body, we can remove the entire 'check if this is a header tr logic of `tr.classList.contains('header')`
// Keep in mind that querySelector returns a nodeList, so if we want to use array methods, we need to covnert it into a real array.
// The original code uses getElementsByTagName, which return a LIVE nodeList, watch out for this difference.
rows = Array.prototype.slice.call(table.querySelectorAll('tbody tr'));
rows.forEach(function(row) {
// Since we don't care in which cell the fitler is contained, we can just check the innerHTML of the entire row.
// This will only fail if the filter typed into the inputs is either 'tr' or 'td'
var hide = (row.innerHTML.indexOf(filter) === -1);
// The alternative is actually checking each cell, but this makes the script take longer:
// var hide = !Array.prototype.slice.call( row.querySelectorAll('td') ).some(function( cell ) {
// return (cell.innerHTML.indexOf( filter ) !== -1);
// });
if (hide) row.classList.add('gone');
else if (row.classList.contains('gone')) row.classList.remove('gone');
});
},
// helper function that we can use to bind the searchTable function to any table and input we want
// We add an onchange event listener, passing it a bound version of searchTable.
bindSearch = function bindSearch(tableID, inputID) {
var input = document.querySelector(inputID),
table = document.querySelector(tableID);
if (table && input) input.addEventListener('change', searchTable.bind(null, table, input));
else alert('Table or input does not exist.');
};
// We can add as many individual inputs / tables as we want by just calling bindSearch with the right ids.
bindSearch('#table1', '#input1');
bindSearch('#table2', '#input2');
.gone {
display: none;
}
<input type="text" id="input1">
<table id="table1">
<thead>
<tr>
<th>header 1</th>
<th>header 2</th>
<th>header 3</th>
<th>header 4</th>
</tr>
</thead>
<tbody>
<tr>
<td>Cell 1-1: foo</td>
<td>Cell 1-2: bar</td>
<td>Cell 1-3: baz</td>
<td>Cell 1-4: foo</td>
</tr>
<tr>
<td>Cell 2-1: apples</td>
<td>Cell 2-2: cherries</td>
<td>Cell 2-3: bananas</td>
<td>Cell 2-4: foo</td>
</tr>
<tr>
<td>Cell 3-1: cars</td>
<td>Cell 3-2: bar</td>
<td>Cell 3-3: planes</td>
<td>Cell 3-4: apples</td>
</tr>
<tr>
<td>Cell 4-1: baz</td>
<td>Cell 4-2: 2017</td>
<td>Cell 4-3: 2010</td>
<td>Cell 4-4: 2001</td>
</tr>
<tr>
<td>Cell 5-1: cars</td>
<td>Cell 5-2: 2017</td>
<td>Cell 5-3: foo</td>
<td>Cell 5-4: undefined</td>
</tr>
</tbody>
</table>
<br>
<br>
<input type="text" id="input2">
<table id="table2">
<thead>
<tr>
<th>header 1</th>
<th>header 2</th>
<th>header 3</th>
<th>header 4</th>
</tr>
</thead>
<tbody>
<tr>
<td>Cell 1-1: foo</td>
<td>Cell 1-2: bar</td>
<td>Cell 1-3: baz</td>
<td>Cell 1-4: foo</td>
</tr>
<tr>
<td>Cell 2-1: apples</td>
<td>Cell 2-2: cherries</td>
<td>Cell 2-3: bananas</td>
<td>Cell 2-4: foo</td>
</tr>
<tr>
<td>Cell 3-1: cars</td>
<td>Cell 3-2: bar</td>
<td>Cell 3-3: planes</td>
<td>Cell 3-4: apples</td>
</tr>
<tr>
<td>Cell 4-1: baz</td>
<td>Cell 4-2: 2017</td>
<td>Cell 4-3: 2010</td>
<td>Cell 4-4: 2001</td>
</tr>
<tr>
<td>Cell 5-1: cars</td>
<td>Cell 5-2: 2017</td>
<td>Cell 5-3: foo</td>
<td>Cell 5-4: undefined</td>
</tr>
</tbody>
</table>
html:
<table id="table2">
<thead></thead>
<tbody>
<tr></tr> <tr></tr>
</tbody>
</table>
js:
var table1 = document.getElementById("table1");
var table2 = document.getElementById("table2");
searchtable(table1);
searchtable(table2);
function searchtable(table) {
var input, filter, table, tr, td, i;
input = document.getElementById("myInput");
filter = input.value.toUpperCase();
tr = table.getElementsByTagName("tr");
th = table.getElementsByTagName("th");
for (i = 1; i < tr.length; i++) {
if (!tr[i].classList.contains('header')) {
td = tr[i].getElementsByTagName("td"),
match = false;
for (j = 0; j < td.length; j++) {
if (td[j].innerHTML.toUpperCase().indexOf(filter) > -1) {
match = true;
break;
}
}
if (!match) {
tr[i].style.display = "none";
} else {
tr[i].style.display = "";
}
}
}
}
Related
I have a table like this
In which I have different city where we have demand-supply of different products.
Now what I want as here demand is different for all the products However supply is the same on all of three product, so I want that table looks like in this manner.
What I want to do is I want only to show the supply column once in the last of the table. This has to be done dynamically as in the future we have multiple products
Can anyone help me with this?
What the code below does is:
Identify the positions of the "Supply"'s and store them in ind array, in this case will be [3, 5, 7]
Loops through ind except for the last element 7(as one "Supply" will be left) and hide all td's; $("td:nth-child("3"), $("td:nth-child("5")
The "Demand"s that precede each of these elements will be assigned two spaces.
let ind = [];
$("td:contains('Supply')").each(function (index) {
ind.push($(this).index() + 1);
});
$(".hide").on("click", function () {
for (let i = 0; i < ind.length - 1; i++) {
let el = $("td:nth-child(" + ind[i] + ")");
el.prev().attr("colspan", "2");
el.hide();
}
});
table,
th,
td {
border: 1px solid black;
border-collapse: collapse;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<tr>
<th>City</th>
<th colspan="2">Product 1</th>
<th colspan="2">Product 2</th>
<th colspan="2">Product 3</th>
</tr>
<tr>
<td></td>
<td>Demand</td>
<td>Supply</td>
<td>Demand</td>
<td>Supply</td>
<td>Demand</td>
<td>Supply</td>
</tr>
<tr>
<td>City 1</td>
<td>50$</td>
<td>60$</td>
<td>90$</td>
<td>60$</td>
<td>100$</td>
<td>60$</td>
</tr>
<tr>
<td>City 2</td>
<td>50$</td>
<td>60$</td>
<td>90$</td>
<td>60$</td>
<td>100$</td>
<td>60$</td>
</tr>
<tr>
<td>City 3</td>
<td>50$</td>
<td>60$</td>
<td>90$</td>
<td>60$</td>
<td>100$</td>
<td>60$</td>
</tr>
<tr>
<td>City 4</td>
<td>50$</td>
<td>60$</td>
<td>90$</td>
<td>60$</td>
<td>100$</td>
<td>60$</td>
</tr>
</table>
<button class="hide">Hide</button>
I am trying to get the value of the cell right of the cell where i click.
But right now I get the value of the cell I want, but I can click any cell in that row and get the desired value. But it should only be possible with the first column. So I click the any cell in the first column and I wanna get it's next neighbour cell value.
document.querySelector("#tableEventListId").addEventListener("click",event => {
let dataTr = event.target.parentNode;
let deleteEventId = dataTr.querySelectorAll("td")[1].innerText;
console.log(deleteEventId);
alert(deleteEventId);
Any help?
You can use nextElementSibling
document.getElementById('table1').onclick = function(event){
//REM: Target
var tElement = event.target;
if(
//REM: Only cells (=<td>)
tElement.tagName === 'TD' &&
//REM: Only first column cells
tElement.parentNode.firstElementChild === tElement
){
//REM: Next Elementsibling of Target or Null
var tNext = tElement.nextElementSibling;
if(tNext){
console.log('TD: ', tElement.textContent);
console.log('Next: ', tElement.nextElementSibling.textContent)
}
}
}
table, td{
border: 1px solid black
}
<table id = 'table1'>
<thead>
<tr>
<th>A</th>
<th>B</th>
<th>C</th>
</tr>
</thead>
<tbody>
<tr>
<td>A1</td>
<td>B1</td>
<td>C1</td>
</tr>
<tr>
<td>A2</td>
<td>B2</td>
<td>C2</td>
</tr>
<tr>
<td>A3</td>
<td>B3</td>
<td>C3</td>
</tr>
</tbody>
</table>
There is no HTML, so I can assume it's something like
<table border="1">
<tr>
<td class="first-column">1.1 (click here)</td>
<td>1.2</td>
<td>1.3</td>
</tr>
<tr>
<td class="first-column">2.1 (click here)</td>
<td>2.2</td>
<td>2.3</td>
</tr>
</table>
According to this HTML, you can try
const firstColumns = document.querySelectorAll(".first-column");
for (let i = 0; i < firstColumns.length; i++) {
firstColumns[i].addEventListener("click", function(event) {
let dataTr = event.target.parentNode;
let deleteEventId = dataTr.querySelectorAll("td")[1].innerText;
console.log(deleteEventId);
alert(deleteEventId);
});
}
Have a look https://jsfiddle.net/vyspiansky/k2toLd8w/
I would recommend you to a an event on every td element of the table. Then use nextElementSibling to get a next cell.
Look code snippet to see the example.
const cells = document.querySelectorAll('#tableEventListId td');
cells.forEach(cell => cell.onclick = function(){
const nextCell = cell.nextElementSibling;
if (nextCell)
alert(nextCell.innerHTML);
})
<table id="tableEventListId">
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td>
</tr>
<tr>
<td>11</td>
<td>22</td>
<td>33</td>
<td>44</td>
</tr>
<tr>
<td>111</td>
<td>222</td>
<td>333</td>
<td>444</td>
</tr>
<tr>
<td>1111</td>
<td>2222</td>
<td>3333</td>
<td>4444</td>
</tr>
</table>
If you want it to work only for cells at first column change the selector to #tableEventListId td:first-child.
Problem
I have a table with one or more empty rows. How to hide empty rows from the table?
For example
1 - John | Alfredo
2 - Mark | Zuck
3 - |
4 - Carl | Johnson
In this case, I'd like to delete the third row.
Step Tried
I found how to delete a specific row, what about deleting all the empty rows?
deleteEmptyRows();
function deleteEmptyRows() {
var myTable = document.getElementById("myTable")
var rowToDelete = 2;
myTable.deleteRow(rowToDelete)
}
<table border="1" cellspacing="1" cellpadding="1" id ="myTable">
<tbody>
<tr>
<td>John</td>
<td>Alfredo</td>
</tr>
<tr>
<td>Mark</td>
<td>Zuck</td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
<tr>
<td>Carl</td>
<td>Johnson</td>
</tr>
</tbody>
</table>
This is how you can dynamically hide empty table rows with javascript.
deleteEmptyRows();
function checkIfCellsAreEmpty(row) {
var cells = row.cells;
var isCellEmpty = false;
for(var j = 0; j < cells.length; j++) {
if(cells[j].innerHTML !== '') {
return isCellEmpty;
}
}
return !isCellEmpty;
}
function deleteEmptyRows() {
var myTable = document.getElementById("myTable");
for(var i = 0; i < myTable.rows.length; i++) {
var isRowEmpty = checkIfCellsAreEmpty(myTable.rows[i]);
if (isRowEmpty) {
myTable.rows[i].style.display = "none";
}
}
}
<table border="1" cellspacing="1" cellpadding="1" id ="myTable">
<tbody>
<tr>
<td>John</td>
<td>Alfredo</td>
</tr>
<tr>
<td>Mark</td>
<td>Zuck</td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
<tr>
<td>Carl</td>
<td>Johnson</td>
</tr>
</tbody>
</table>
Here, a simple method for row is empty (this allows us to check for other conditions easily later).
Loop over rows and call remove if empty.
const rowIsEmpty = (tr) => Array.from(tr.querySelectorAll('td')).every(td => td.innerText === "");
deleteEmptyRows();
function deleteEmptyRows() {
var myTable = document.getElementById("myTable");
myTable.querySelectorAll('tr').forEach(tr => {
if(rowIsEmpty(tr)) tr.remove();
});
}
<table border="1" cellspacing="1" cellpadding="1" id ="myTable">
<tbody>
<tr>
<td>John</td>
<td>Alfredo</td>
</tr>
<tr>
<td>Mark</td>
<td>Zuck</td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
<tr>
<td>Carl</td>
<td>Johnson</td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
</tbody>
</table>
Was answered in another thread.
Jquery: hiding empty table rows
Loops through all table tr rows, and checks td lengths. If the td length is empty will hide.
$("table tr").each(function() {
let cell = $.trim($(this).find('td').text());
if (cell.length == 0){
console.log('Empty cell');
$(this).addClass('nodisplay');
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<tr>
<td>1</td>
</tr>
<tr>
<!-- Will hide --> <td></td>
</tr>
</table>
With native Javascript:
function removeRow(src) {
var tableRows = document.getElementById(src).querySelectorAll('tr');
tableRows.forEach(function(row){
if((/^\s*$/).test(row.innerText)){
row.parentNode.removeChild(row);
}
});
}
removeRow('myTable');
The only problem is when you have some other characters in the row, except the whitespaces. This regex checks for blank characters, but if u have a dot inside or any other non empty character, it will fail.
Table .cells will return all the inner cells in table. It is working fine in IE.But in Chrome .cells will return 'undefined' because no such property exists.We have to loop through each row to find the cells.Is there any other way to get all the cells in chrome?
function myFunction() {
var x = document.getElementById("myTable").cells.length;
document.getElementById("demo").innerHTML = "Found " + x + " cells in
the first tr element.";
}
<table id="myTable">
<tr>
<td>cell 1</td>
<td>cell 2</td>
</tr>
<tr>
<td>cell 3</td>
<td>cell 4</td>
</tr>
</table>
There is nothing called document.getElementById("myTable").cells.length
the .cells actually returns nothing, thus your x variable returns undefined and you don't get the cell numbers.
Instead, you can do the following:
function myFunction() {
var x = document.getElementById("myTable");
// if you need all the cells which is td elements
var cells = x.getElementsByTagName('td');
// if you need only cells in a single row which is a tr element
var cellsPerRow = x.getElementsByTagName('tr')[0].getElementsByTagName('td');
document.getElementById("demo").innerHTML = "Found " + cellsPerRow.length + " cells in the first tr element." + "And " + cells.length + " cells in total" ;
}
myFunction();
<table id="myTable">
<tr>
<td>cell 1</td>
<td>cell 2</td>
</tr>
<tr>
<td>cell 3</td>
<td>cell 4</td>
</tr>
</table>
<div id='demo'></div>
I would like to transfer a particular column only. Please help me.
Here is my code:
btnAdd.on('click', function () {
var trItem = $(this).closest("tr").clone();
trItem.find("input").remove();
trItem.add("<tr>").append("</tr>");
$("#products").append(trItem);
console.log(btnAdd);
})
thank you so much.
You need to specify all cells need to be cloned.
Function "funcCloneRow" will clone a row (tr) and add cell's content by "tdKeyArr".
Remember that "tdKeyArr" is an array contain choosen cells's position, like this:
$(function() {
var funcCloneRow = function($table1, $table2, trIndex, tdKeyArr) {
// define. If tdKeyArr == undefinded, all the cell in choosen tr will be cloned
if($table1 == undefined || $table2 == undefined || trIndex == undefined) {
return;
}
// clone row
var $tr = $table1.find('tr').eq(trIndex).clone();
// get cell content
if(tdKeyArr != undefined) {
$tr.children('td').text('');
for (var i = 0; i < tdKeyArr.length; i++) {
$tr.children('td').eq(tdKeyArr[i]).html($table1.find('tr').eq(trIndex).children('td').eq(tdKeyArr[i]).html());
}
}
// append new row to second table
if ($table2.children('tbody').length) {
$table2.children('tbody').append($tr);
}
else {
$table2.append($tr);
}
}
$('table button').on('click', function(event) {
funcCloneRow($('#table1'), $('#table2'), $(this).closest('tr').index(), [$(this).parent().index(), 1]);
});
});
table {
float:left;
margin-right:100px;
border-collapse:collapse;
text-align:center;
vertical-align:top;
}
table th,
table td {
border:1px solid #000;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<body>
<table id="table1">
<tr>
<th>head 1</th>
<th>head 2</th>
<th>head 3</th>
</tr>
<tr>
<td>row 1</td>
<td>row 1</td>
<td><button>Append</button></td>
</tr>
<tr>
<td>row 2</td>
<td>row 2</td>
<td><button>Append</button></td>
</tr>
<tr>
<td>row 3</td>
<td>row 3</td>
<td><button>Append</button></td>
</tr>
</table>
<table id="table2">
<tr>
<th>head 1</th>
<th>head 2</th>
<th>head 3</th>
</tr>
</table>
</body>