Count visible rows in html table using Javascript - javascript

How to count total visible rows in html table using javascript, I have a code below that filters table rows while typing, I would like to see the number count of visible rows displayed in an innerHTML whole typing automatically
i tried this line of code but i dont see any results in the innerHTML
document.getElementById("statistic").innerHTML = tr[i].length;
FULL CODE
function myFunction() {
// Declare variables
var input, filter, table, tr, td, i, txtValue;
input = document.getElementById("myInput");
filter = input.value.toUpperCase();
table = document.getElementById("MyTable");
tr = table.getElementsByTagName("tr");
// Loop through all table rows, and hide those who don't match the search query
for (i = 0; i < tr.length; i++) {
td = tr[i].getElementsByTagName("td")[1]; // change number to any other number to target column for table search
if (td) {
txtValue = td.textContent || td.innerText;
if (txtValue.toUpperCase().indexOf(filter) > -1) {
tr[i].style.display = "";
document.getElementById("statistic").innerHTML = tr[i].length;
} else {
tr[i].style.display = "none";
}
}
}

function myFunction() {
// Declare variables
var input, filter, table, tr, td, i, txtValue;
input = document.getElementById("myInput");
filter = input.value.toUpperCase();
table = document.getElementById("MyTable");
tr = table.getElementsByTagName("tr");
// Loop through all table rows, and hide those who don't match the search query
rowsFound = [];
for (i = 0; i < tr.length; i++) {
td = tr[i].getElementsByTagName("td")[1]; // change number to any other number to target column for table search
if (td) {
txtValue = td.textContent || td.innerText;
if (txtValue.toUpperCase().indexOf(filter) > -1) {
tr[i].style.display = "";
rowsFound.push(1)
} else {
tr[i].style.display = "none";
}
}
}
document.getElementById("statistic").innerHTML = rowsFound.length;
}
myFunction()
<input id="myInput" onInput="myFunction();">
<table id="MyTable">
<div id="statistic"></div>
<tr>
<td>A</td>
<td>A</td>
<td>A</td>
</tr>
<tr>
<td>B</td>
<td>B</td>
<td>B</td>
</tr>
<tr>
<td>B</td>
<td>B</td>
<td>B</td>
</tr>
<tr>
<td>C</td>
<td>C</td>
<td>C</td>
</tr>
</table>

something like that ?
const
txt2search = document.querySelector('#txt-2-search')
, searchResult = document.querySelector('#search-result')
, btSearch = document.querySelector('#bt-search')
, myTable = document.querySelector('#my-table')
;
btSearch.onclick =()=>
{
let
counter = 0
, txt = txt2search.value.trim()
, Regtxt = new RegExp(txt, 'i')
;
myTable.querySelectorAll('tr.noDisplay').forEach(tr => tr.classList.remove('noDisplay'));
if (txt==='')
{
searchResult.textContent = 'nothing to search...';
return;
}
for (let tr of myTable.tBodies[0].rows)
{
if (Regtxt.test(tr.innerText )) counter++;
else tr.classList.add('noDisplay');
}
searchResult.textContent =
(counter===0) ? 'no result' : `${counter} element(s) found`;
}
body {
font-family : Arial, Helvetica, sans-serif;
font-size : 16px;
margin : 1rem;
}
table {
border-collapse : separate;
border-spacing : 1px;
background-color : lightslategrey;
}
th { background: cadetblue; padding: .3em .6em; }
td { background: whitesmoke; padding: .2em .5em; }
tr *:first-child { text-align: center; font-style: oblique; }
tr * { white-space: nowrap; }
.noDisplay { display: none; }
caption {
text-align : left;
padding : .4rem;
font-size : 1.2rem;
background : #a0dbdd;
}
#search-result {
float : right;
font-size : .9rem;
}
<table id="my-table">
<caption>
Find :
<input type="text" id="txt-2-search" placeholder="show rows with...?">
<button id="bt-search"> show rows </button>
<span id="search-result">.</span>
</caption>
<thead>
<tr>
<th>#</th><th>First Name</th><th>Last Name</th><th>Address</th><th>Age</th><th>Date of Birth</th><th>Nationality</th>
</tr>
</thead>
<tbody>
<tr><td>1</td><td>John</td><td>Smith</td><td>Pearse Street</td><td>45</td><td>01/10/1977</td><td>English</td></tr>
<tr><td>11</td><td>Tim</td><td>Green</td><td>Rosedale Avenue</td><td>23</td><td>17/04/1999</td><td>American</td></tr>
<tr><td>114</td><td>Tom</td><td>Deane</td><td>Greenwood Road</td><td>42</td><td>27/11/1980</td><td>English</td></tr>
<tr><td>208</td><td>Anna</td><td>Green</td><td>Rosedale Avenue</td><td>23</td><td>11/06/1999</td><td>Scottish</td></tr>
<tr><td>259</td><td>Rachel</td><td>Waters</td><td>Station Road</td><td>87</td><td>11/02/1936</td><td>Irish</td></tr>
<tr><td>1</td><td>George</td><td>Taylor</td><td>Beach Avenue</td><td>52</td><td>30/07/1971</td><td>South African</td></tr>
<tr><td>1</td><td>Neil</td><td>Smyth</td><td>Beach Road</td><td>6</td><td>15/12/2016</td><td>Australian</td></tr>
<tr><td>1</td><td>Sarah</td><td>Smyth</td><td>Beach Road</td><td>30</td><td>06/01/1993</td><td>Australian</td></tr>
</tbody>
</table>

Related

How to Filter Items From A Table with Search

<input type="text" id="inputhair" onkeyup="hair()" placeholder="hair color...">
<table id="customers" class="customers">
<tr class="parent" data-toggle="toggle">
<th id="rank" style="text-align:center">#</th>
<th id="name" style="text-align:center">Name</th>
<th id="name" style="text-align:center"></th>
</tr>
<tbody class="content" >
<div class="1">
<tr>
<td>1</td>
<td class="name">Object A</td>
<td class="down"><button onclick="toggleText()" type="button" class="collapsible" id="1">+</button></td>
</tr>
</div>
<tr class="panel" id="1a" colspan="3">
<div class="panel" >
<td class="expand" >
<div class="hair">Black</div>
</td>
</div>
</tr>
</tbody>
</table>
I'm trying to filter out two rows (name and details) of an object from this table if it doesn't match what is searched, but it is not doing anything on the actual website. Please respond if you can. Thank you
Number
Name
1
Object A
+
Black
I tried doing (I have more objects like object 1 all with two lines)...
function hair() {
// Declare variables
var input, filter, table, tr, td, i, txtValue;
input = document.getElementById("inputhair");
filter = input.value.toUpperCase();
table = document.getElementById("customers");
tr = table.getElementsByTagName("tr");
// // Loop through all table rows, and hide those who don't match the search query
// for (i = 1; i < tr.length; i++) {
// td = tr[i].getElementsByTagName("td")[0];
// var hairColor = document.getElementsByClassName("hair")[i/2].innerHTML;
// if (hairColor) {
// if (hairColor.toUpperCase().indexOf(filter) > -1) {
// tr[i].style.display = "";
// } else {
// tr[i].style.display = "none";
// tr[i-1].style.display = "none";
// }
// }
// }
for (i = 1; i < tr.length; i++) {
td = tr[i].getElementsByTagName("td")[0];
var hairColor = document.getElementsByClassName("hair")[i/2].innerHTML;
if (hairColor) {
if ((hairColor.toUpperCase).includes(filter)) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
tr[i-1].style.display = "none";
}
}
}
}

How do I get my search function work to filter searched items from table?

I've made a table filled with data retreived from a JSON file. Now I'm trying to make a searchbar that filters searched items and only shows the table rows of the items searched for. The code of the function I'm using now is:
//Search function
function searchTable() {
var input, filter, found, table, tr, td, i, j;
input = document.getElementsByClassName("searchBar");
filter = input.value.toUpperCase();
table = document.getElementById("productTable");
tr = table.getElementsByTagName("tr");
for (i = 0; i < tr.length; i++) {
td = tr[i].getElementsByTagName("td");
for (j = 0; j < td.length; j++) {
if (td[j].innerHTML.toUpperCase().indexOf(filter) > -1) {
found = true;
}
}
if (found) {
tr[i].style.display = "";
found = false;
} else {
tr[i].style.display = "none";
}
}
}
});
This is the HTML of the table I'm trying to apply the filter to:
<input class="form-control searchBar" type="text" name="search" placeholder="search">
<table class="table table-hover">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Product Name</th>
<th scope="col">Free Stock</th>
<th scope="col">Price</th>
<th scope="col">Actions</th>
</tr>
</thead>
<tbody id="productTable">
<tr>
</tr>
</tbody>
</table>
Here is the best solution for searching inside HTML table while covering all of the table, (all td, tr in the table), pure javascript and as short as possible:
<body style="background:red;">
<input id='myInput' onkeyup='searchTable()' type='text'>
<table id='myTable'>
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Product Name</th>
<th scope="col">Free Stock</th>
<th scope="col">Price</th>
<th scope="col">Actions</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Green</td>
<td>Lorem</td>
<td>Ipsum</td>
<td>button</td>
</tr>
<tr>
<td>2</td>
<td>Green</td>
<td>elit</td>
<td>Mumbai</td>
<td>button</td>
</tr>
<tr>
<td>3</td>
<td>Green</td>
<td>sud</td>
<td>Dummy</td>
<td>button</td>
</tr>
</tbody>
</table>
<script>
function searchTable() {
var input, filter, found, table, tr, td, i, j;
input = document.getElementById("myInput");
filter = input.value.toUpperCase();
table = document.getElementById("myTable");
tr = table.getElementsByTagName("tr");
for (i = 0; i < tr.length; i++) {
td = tr[i].getElementsByTagName("td");
for (j = 0; j < td.length; j++) {
if (td[j].innerHTML.toUpperCase().indexOf(filter) > -1) {
found = true;
}
}
if (found) {
tr[i].style.display = "";
found = false;
} else {
tr[i].style.display = "none";
}
}
}
</script>
</body>
The problem is getElementsByClassName does not return an element. Instead, it returns a NodeList. If you only have a single element with class=“searchBar” then you would reference as:
input = document.getElementsByClassName("searchBar")[0];
Updated script with your existing ID is
function searchTable() {
var input, filter, found, table, tr, td, i, j;
input = document.getElementsByClassName("searchBar")[0];
filter = input.value.toUpperCase();
table = document.getElementById("productTable");
tr = table.getElementsByTagName("tr");
for (i = 0; i < tr.length; i++) {
td = tr[i].getElementsByTagName("td");
for (j = 0; j < td.length; j++) {
if (td[j].innerHTML.toUpperCase().indexOf(filter) > -1) {
found = true;
}
}
if (found) {
tr[i].style.display = "";
found = false;
} else {
tr[i].style.display = "none";
}
}
}
However, if you are only going to have one of these elements, I suggest giving it an id and use getElementById and then you will actually get an element.

How to create a JavaScript loop that adds DOM properties to attributes?

I have a table with cells that are not contentEditable. However, using a JavaScript loop or function, I would like to make them so.
I understand that it is very simple to do this manually for each cell, and this would probably be easier for a table with only a few cells, but I would like to quicken this process with a loop/function for the table could become much larger, and the time spent manually setting each cell to be contentEditable would be tedious.
Below is a quick example that displays a table calculator, un-editable at present. But using a loop or function, I'd like to make every cell in the right column set to .contentEditable = true in the DOM. I imagine that the parameters would look something like (var i = 0; l != rows.length; i < l; i+2), but I'm struggling with what the statements following the argument would have to be for the loop/function to work. Any help would be much appreciated!
function myFunction() {
var jack2 = document.getElementById("jack").innerText;
var john2 = document.getElementById("john").innerText;
var joe2 = document.getElementById("joe").innerText;
var total2 = (parseInt(jack2) || 0) + (parseInt(john2) || 0) + (parseInt(joe2) || 0);
document.getElementById("total").innerHTML = total2;
}
table {
width: 100%;
}
table,
tr,
th,
td {
border: 1px solid gray;
border-collapse: collapse;
font-family: Arial;
margin: 5px;
}
<table>
<caption>Weight Calculator</caption>
<tr class="cell">
<th>Person</th>
<th>Weight (kg)</th>
</tr>
<tr class="cell">
<td>Jack</td>
<td id="jack" oninput="myFunction()">1</td>
</tr>
<tr class="cell">
<td>John</td>
<td id="john" oninput="myFunction()">2</td>
</tr>
<tr class="cell">
<td>Joe</td>
<td id="joe" oninput="myFunction()">3</td>
</tr>
<tr class="cell">
<td>Total</td>
<td id="total"></td>
</tr>
</table>
Get all cell in the tabel that have a left neigbour (the header is not effected because there are th and not td). Add to each of these cells your attribute.
Edited: For getting the totalsum add an eventlistener on each td that calls the calc-function if the content changes.
function myFunction() {
let weightCells = document.querySelectorAll("table tr:not(:last-child) td ~ td");
weightCells.forEach(td => {
td.setAttribute('contentEditable', true);
td.addEventListener ("change", calcSum());
});
}
function calcSum() {
let sum=0;
let weightCells = document.querySelectorAll("table tr td ~ td");
let count = weightCells.length-1;
for (i=0; i<count; i++) {
sum += parseInt(weightCells[i].innerHTML) || 0;
}
weightCells[count].innerHTML = sum;
}
myFunction();
table {
width: 100%;
}
table,
tr,
th,
td {
border: 1px solid gray;
border-collapse: collapse;
font-family: Arial;
margin: 5px;
}
<table>
<caption>Weight Calculator</caption>
<tr class="cell">
<th>Person</th>
<th>Weight (kg)</th>
</tr>
<tr class="cell">
<td>Jack</td>
<td id="jack" oninput="myFunction()">1</td>
</tr>
<tr class="cell">
<td>John</td>
<td id="john" oninput="myFunction()">2</td>
</tr>
<tr class="cell">
<td>Joe</td>
<td id="joe" oninput="myFunction()">3</td>
</tr>
<tr class="cell">
<td>Total</td>
<td id="total"></td>
</tr>
</table>
You can select the whole table, then use querySelectorAll to get all rows then for each rows change the contenteditable for the second td like this
codepen
let table = document.getElementById('table')
let rows = table.querySelectorAll('tr')
rows.forEach(row => {
let tds = row.querySelectorAll('td')
// all the cells of the row
if (tds.length > 0) { // if it is not the header
tds[1].contentEditable = true
// change the contenteditable
}
})
(you need to add an id to your table in case you have more than one table)
<table id="table">
...
</table>

I want to filter the value in a table but I have an error

Cannot read property 'textContent' of undefined
I have that error and I don't now why
I'm a beginner so maybe it's a very simple thing that I don't understand
function price() {
var table, tr, td, input;
table = document.getElementById("myTable");
tr = table.getElementsByTagName("tr");
input = document.getElementById("myInput1");
for (let i = 0; i < tr.length; i++) {
td = tr[i].getElementsByTagName("td")[2];
if ( parseInt(td.textContent) > parseInt(input.value)) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
}
In fact I want to hide in a table the line where their value are bigger than the value writted by the user
That is the base HTML :
<body>
<input type="text" class="fa fa-search" id="myInput1" onkeyup="price()" placeholder="Prix max" title="Ecrivez un prix">
<table id="myTable">
<tr>
<th>Name</th>
<th>Country</th>
<th>Price</th>
</tr>
<template id="listeDestinations">
<tr>
<td>{{pays}}</td>
<td>{{ville}}</td>
<td>{{price}}</td>
</tr>
</template>
</table>
<script src="../javascript/accueil.js"></script>
<script src="../javascript/Destinations.js"></script>
</body>
Thank you in adavance if you help me
This Line tr = table.getElementsByTagName("tr"); will retrieve all tr in your html page and you have 2 tr tags
After that you do for loop and in the first iterator in your for loop you will catch the first tr and after that you will get all td inside this tr tr[i].getElementsByTagName("td")[2];
but your first tr doesn't have any td It has th because of that this line td = tr[i].getElementsByTagName("td")[2]; will return undefined

Filter table with multiple search strings (Vanilla JS)

I'm trying to do this but instead to search within multiple columns of the same table: [https://www.w3schools.com/howto/howto_js_filter_table.asp][1]
In this example above, I would want not only want to filter by "name", but also by "Country".
I found a similar post here, however it's for seven separate columns and there is no other vanilla JS code I could find: [https://stackoverflow.com/questions/47274028/filtering-table-with-multiple-filters?answertab=oldest#tab-top][2]
I tried duplicating the loop (as shown below), but obviously that didn't work because the matches conflict with the first loop.
This is a little too advanced for me and I require a solution. Any help is appreciated.
function myFunction() {
// Declare variables
var input, filter, table, tr, td, i, txtValue;
input = document.getElementById("myInput");
filter = input.value.toUpperCase();
table = document.getElementById("myTable");
tr = table.getElementsByTagName("tr");
// Loop through all table rows, and hide those who don't match the search query
for (i = 0; i < tr.length; i++) {
td1 = tr[i].getElementsByTagName("td")[0];
if (td1) {
txtValue1 = td1.textContent || td1.innerText;
if (txtValue1.toUpperCase().indexOf(filter) > -1) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
}
// this is what i've tried adding, but oviously, it conflicts with the first loop when matching
for (j = 0; j < tr.length; j++) {
td2 = tr[j].getElementsByTagName("td")[1];
if (td2) {
txtValue2 = td2.textContent || td2.innerText;
if (txtValue2.toUpperCase().indexOf(filter) > -1) {
tr[j].style.display = "";
} else {
tr[j].style.display = "none";
}
}
}
}
Maybe this modified function is of help to you. The basic change is that it does not search within individual table cells but within the concatenated text content of a complete table row.
function myFunction() {
var input, filter, table, tr, td, i, txtValue;
input = document.getElementById("myInput");
filter = input.value.toUpperCase();
table = document.getElementById("myTable");
tr = table.getElementsByTagName("tr");
for (i = 0; i < tr.length; i++) {
var rowContent = tr[i].textContent;
rowContent = rowContent.replace(/[\s]+/g, ' ');
//console.log(rowContent);
if (rowContent) {
if (rowContent.toUpperCase().includes(filter)) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
}
}
* {
box-sizing: border-box;
}
#myInput {
background-image: url('/css/searchicon.png');
background-position: 10px 10px;
background-repeat: no-repeat;
width: 100%;
font-size: 16px;
padding: 12px 20px 12px 40px;
border: 1px solid #ddd;
margin-bottom: 12px;
}
#myTable {
border-collapse: collapse;
width: 100%;
border: 1px solid #ddd;
font-size: 18px;
}
#myTable th, #myTable td {
text-align: left;
padding: 12px;
}
#myTable tr {
border-bottom: 1px solid #ddd;
}
#myTable tr.header, #myTable tr:hover {
background-color: #f1f1f1;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h2>My Customers</h2>
<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Search for names.." title="Type in a name">
<table id="myTable">
<tr class="header">
<th style="width:60%;">Name</th>
<th style="width:40%;">Country</th>
</tr>
<tr>
<td>Alfreds Futterkiste</td>
<td>Germany</td>
</tr>
<tr>
<td>Berglunds snabbkop</td>
<td>Sweden</td>
</tr>
<tr>
<td>Island Trading</td>
<td>UK</td>
</tr>
<tr>
<td>Koniglich Essen</td>
<td>Germany</td>
</tr>
<tr>
<td>Laughing Bacchus Winecellars</td>
<td>Canada</td>
</tr>
<tr>
<td>Magazzini Alimentari Riuniti</td>
<td>Italy</td>
</tr>
<tr>
<td>North/South</td>
<td>UK</td>
</tr>
<tr>
<td>Paris specialites</td>
<td>France</td>
</tr>
</table>
</body>
</html>
Split the search string by space and filter the columns for each word. You can use the same for() for both columns. Try this code:
function myFunction() {
var src, input, filter, table, tr, td, i, txtValue;
input = document.getElementById("myInput");
filter = input.value.toUpperCase().trim().split(' ');
table = document.getElementById("myTable");
for (j = 0; j < filter.length; j++) {
tr = table.getElementsByTagName("tr");
src = filter[j].trim();
for (i = 0; i < tr.length; i++) {
td = tr[i].getElementsByTagName("td")[0];
td2 = tr[i].getElementsByTagName("td")[1];
if (src.length>1 && td && td2) {
txtValue = td.textContent || td.innerText;
txtValue2 = td2.textContent || td2.innerText;
if (txtValue.toUpperCase().indexOf(src) > -1 || txtValue2.toUpperCase().indexOf(src) > -1) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
}
}
}
Okay i thought differently my mistake you can separate search function to do easy work and you can try i have modified my code with concatenation of string.
function myFunction() {
var input, filter, table, tr, td, i, txtValue;
input = document.getElementById("myInput");
filter = input.value.toUpperCase();
table = document.getElementById("myTable");
tr = table.getElementsByTagName("tr");
search(input, filter, table, tr);
}
function search(input, filter, table, tr){
for (i = 1; i < tr.length ; i++) {
td = tr[i].getElementsByTagName("td");
var concat='';
for (j = 0; j < td.length; j++) {
txtValue = td[j].textContent || td[j].innerText;
concat += txtValue+' ';
}
console.log(concat);
if (td) {
if (concat.toUpperCase().search(filter) > -1) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
}
}

Categories

Resources