Using the table sort on w3schools as a base, how can I keep my table header from disappearing on searching the table?
$(document).ready(function(){
$('#search-attorneys').on('keyup', function(){
var input, filter, table, tr, td, i;
input = $("#search-attorneys");
filter = $("#search-attorneys").val().toUpperCase();
table = $("#attorneys");
tr = $("tr");
for (i = 0; i < tr.length; i++) {
tds = tr[i].getElementsByTagName("td");
var found = false;
for (j = 0; j < tds.length; j++) {
td = tds[j];
if (td) {
if (td.innerHTML.toUpperCase().indexOf(filter) > -1) {
found = true;
break;
}
}
}
if (found) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
});
});
JSFIDDLE: LINK
You need to do change in first for loop:-
for (i = 1; i < tr.length; i++) { // not start with 0 start with 1.
Means leave table <thead><tr> and then start searching in rest <tr>.
Note:- check it and if you are facing any problem. I will create an example for you.
This can be easily achieved by putting the rows in a tbody, and changing the variabl;e tr selector.
$(document).ready(function(){
$('#search-attorneys').on('keyup', function(){
var input, filter, table, tr, td, i;
input = $("#search-attorneys");
filter = $("#search-attorneys").val().toUpperCase();
table = $("#attorneys");
tr = $("tbody tr"); // CHANGED
for (i = 0; i < tr.length; i++) {
tds = tr[i].getElementsByTagName("td");
var found = false;
for (j = 0; j < tds.length; j++) {
td = tds[j];
if (td) {
if (td.innerHTML.toUpperCase().indexOf(filter) > -1) {
found = true;
break;
}
}
}
if (found) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text" id="search-attorneys" placeholder="Search for names.." title="Type in a name">
<table id="attorneys">
<thead class="cf">
<tr>
<th class="numeric">attorney</th>
<th class="numeric">location</th>
<th class="numeric">practice area</th>
<th class="numeric">email</th>
<th class="numeric">phone</th>
</tr>
</thead>
<tbody>
<tr>
<td data-title="location">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>
</tbody>
</table>
Related
I have the following JS code to import from a HTML table to Excel.
function fnExcelReport(){
var tab_text="<table border='2px'><tr bgcolor='#87AFC6'>";
var textRange; var j=0;
tab = document.getElementById('myTable'); // id of table
for(j = 0 ; j < tab.rows.length ; j++)
{
tab_text=tab_text+tab.rows[j].innerHTML+"</tr>";
}
tab_text=tab_text+"</table>";
tab_text= tab_text.replace(/<A[^>]*>|<\/A>/g, "");//remove if u want links in your table
tab_text= tab_text.replace(/<img[^>]*>/gi,""); // remove if u want images in your table
tab_text= tab_text.replace(/<input[^>]*>|<\/input>/gi, ""); // reomves input params
var ua = window.navigator.userAgent;
var msie = ua.indexOf("MSIE ");
if (msie > 0 || !!navigator.userAgent.match(/Trident.*rv\:11\./)) // If Internet Explorer
{
txtArea1.document.open("txt/html","replace");
txtArea1.document.write(tab_text);
txtArea1.document.close();
txtArea1.focus();
sa=txtArea1.document.execCommand("SaveAs",true,"Say Thanks to Sumit.xls");
}
else //other browser not tested on IE 11
sa = window.open('data:application/vnd.ms-excel,' + encodeURIComponent(tab_text));
return (sa);
}
I don't want to import the last column from the table. How can i do it?
If you use jquery then you can remove the last column easily by using last child selector
$('#myTable tr').find('th:last-child, td:last-child').remove()
But if you want to use JS, then try like below (it's just a dummy table for example purpose)
// GET ALL THE ROW OF THE TABLE USING TABLE ID
var tRow = document.getElementById('myTable').rows;
// LOOPING OVER EACH ROW
for (var i=0; i< tRow.length; i++) {
tRow[i].deleteCell(-1); //DELETE THE LAST COLUMN
}
for(j = 0 ; j < tRow.length ; j++)
{
console.log(tRow[j].innerHTML);
}
table {
font-family: arial, sans-serif;
border-collapse: collapse;
width: 100%;
}
td, th {
border: 1px solid #dddddd;
text-align: left;
padding: 8px;
}
tr:nth-child(even) {
background-color: #dddddd;
}
<table id="myTable">
<tr>
<th>Company</th>
<th>Contact</th>
<th>Country</th>
<th>ISO Code</th>
</tr>
<tr>
<td>Alfreds Futterkiste</td>
<td>Maria Anders</td>
<td>Germany</td>
<td>AL</td>
</tr>
<tr>
<td>Centro comercial Moctezuma</td>
<td>Francisco Chang</td>
<td>Mexico</td>
<td>MEX</td>
</tr>
<tr>
<td>Ernst Handel</td>
<td>Roland Mendel</td>
<td>Austria</td>
<td>AUS</td>
</tr>
<tr>
<td>Island Trading</td>
<td>Helen Bennett</td>
<td>UK</td>
<td>UK</td>
</tr>
<tr>
<td>Laughing Bacchus Winecellars</td>
<td>Yoshi Tannamuri</td>
<td>Canada</td>
<td>CAD</td>
</tr>
<tr>
<td>Magazzini Alimentari Riuniti</td>
<td>Giovanni Rovelli</td>
<td>Italy</td>
<td>ITL</td>
</tr>
</table>
So after getting the table data in your code, you can apply any of the methods you prefer.
If you choose second method then your code will be like below:
tab = document.getElementById('myTable'); // id of table
tabRows = tab.rows; //get the rows
for (var i=0; i< tabRows.length; i++) {
tabRows[i].deleteCell(-1); //DELETE THE LAST ONE
}
for(j = 0 ; j < tabRows.length ; j++) //DO YOUR ACTUAL WORK
{
//Your conditions
}
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.
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>
EDIT: Nevermind, I just fixed my problem by making the header a separate table to hold all of my tags
So I have a HTML table and I want to have a search bar to search the table because it's pretty large. I tried copying the code from this W3 schools tutorial (https://www.w3schools.com/howto/howto_js_filter_lists.asp) and I got it modified and working for the table, but only if I don't use any rows that include tags.
Here's my currently working code (I commented out the code segment that was giving me trouble):
<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Search for names.." title="Type in a name">
<table id="myUL" class="BuyBooksTable">
<!--<tr>
<th colspan="3">Books</th>
</tr>
<tr>
<th>Item</th>
<th>Price</th>
<th>Purchase Item</th>
</tr> -->
<div id="myULSmaller">
<tr>
<td>Alice</td>
<td>Price</td>
<td>Purchase Item</td>
</tr>
<tr>
<td>Bob</td>
<td>Price</td>
<td>Purchase Item</td>
</tr>
<tr>
<td>Carol</td>
<td>Price</td>
<td>Purchase Item</td>
</tr>
</div>
</table>
<script>
function myFunction() {
// Declare variables
var input, filter, ul, li, a, i, txtValue;
input = document.getElementById('myInput');
filter = input.value.toUpperCase();
ul = document.getElementById("myUL");
li = ul.getElementsByTagName('tr');
// Loop through all list items, and hide those who don't match the search query
for (i = 0; i < li.length; i++) {
a = li[i].getElementsByTagName("td")[0];
txtValue = a.textContent || a.innerText;
if (txtValue.toUpperCase().indexOf(filter) > -1) {
li[i].style.display = "";
} else {
li[i].style.display = "none";
}
}
}
</script>
Using querySelectorAll.
Also, you can use <tbody> rather than to have a div inside your table.
function myFunction(e) {
let searchTerm = e.value.toLocaleLowerCase();
var trs = document.querySelectorAll('table tbody tr');
[].forEach.call(trs, function(tr) { // all trs
[].forEach.call(tr.children, function(td) { // all tds
if (td.getAttribute('search')) { // check if the td needs to be considers for search criteria
if (td.innerText.toLocaleLowerCase().includes(searchTerm)) {
tr.style.display = "";
} else {
tr.style.display = "none";
}
}
});
});
}
<input type="text" id="myInput" onkeyup="myFunction(this)" placeholder="Search for names.." title="Type in a name">
<table id="myUL" class="BuyBooksTable">
<tr>
<th colspan="3">Books</th>
</tr>
<tr>
<th>Item</th>
<th>Price</th>
<th>Purchase Item</th>
</tr>
<tbody>
<tr>
<td search="true">Alice</td>
<td>Price</td>
<td>Purchase Item</td>
</tr>
<tr>
<td search="true">Bob</td>
<td>Price</td>
<td>Purchase Item</td>
</tr>
<tr>
<td search="true">Carol</td>
<td>Price</td>
<td>Purchase Item</td>
</tr>
</tbody>
</table>
You need to check that the value a in the line a = li[i].getElementsByTagName("td")[0]; exists. Try this:
<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Search for names.." title="Type in a name">
<table id="myUL" class="BuyBooksTable">
<tr>
<th colspan="3">Books</th>
</tr>
<tr>
<th>Item</th>
<th>Price</th>
<th>Purchase Item</th>
</tr>
<div id="myULSmaller">
<tr>
<td>Alice</td>
<td>Price</td>
<td>Purchase Item</td>
</tr>
<tr>
<td>Bob</td>
<td>Price</td>
<td>Purchase Item</td>
</tr>
<tr>
<td>Carol</td>
<td>Price</td>
<td>Purchase Item</td>
</tr>
</div>
</table>
<script>
function myFunction() {
// Declare variables
var input, filter, ul, li, a, i, txtValue;
input = document.getElementById('myInput');
filter = input.value.toUpperCase();
ul = document.getElementById("myUL");
li = ul.getElementsByTagName('tr');
// Loop through all list items, and hide those who don't match the search query
for (i = 0; i < li.length; i++) {
a = li[i].getElementsByTagName("td")[0];
//If a doesn't exist, carry on looping:
if (!a) {
continue;
}
txtValue = a.textContent || a.innerText;
if (txtValue.toUpperCase().indexOf(filter) > -1) {
li[i].style.display = "";
} else {
li[i].style.display = "none";
}
}
}
</script>
just use :nth-child(n+3) selector
document.querySelectorAll('#myUL tr:nth-child(n+3)')
or edit your code like
...
//ul = document.getElementById("myUL");
ul = document.getElementById("myULSmaller");
...
or use this
let trs = document.querySelectorAll('#myUL tr:nth-child(n+3)');
function myFunction() {
let filter = this.value.trim().toLowerCase();
let emptyStr = filter.length == 0;
trs.forEach(function(el) {
el.style.display = emptyStr || el.textContent.toLowerCase().includes(filter)?"":"none";
});
}
Nidhins answer is great but if you need to search all columns you need to modify it.
I include a variable to track if any cell in the row matches. Highlite that cell and display the row
//Set event listener
document.getElementById("myInput").addEventListener("keyup",function(){
var normalisedSearch = this.value.toLocaleLowerCase();
//Grab the search tr in the table body
var searchTrs = document.querySelectorAll("#myUL>tbody>tr");
//iterate the cells in the tr
[].forEach.call(searchTrs,function(tr){
var visible = false;
//iterate the cells in the row
var searchTds = tr.querySelectorAll("td");
[].forEach.call(searchTds, function(td){
if(td.innerText.toLocaleLowerCase().includes(normalisedSearch)){
visible = true;
td.style.backgroundColor = normalisedSearch !== "" ? "#CCC" : "";
}else{
td.style.backgroundColor = "";
}
});
//Sit vidibility of the row
tr.style.display = visible ? "" : "none";
});
});
<input type="text" id="myInput" placeholder="Search for names.." title="Type in a name">
<table id="myUL" class="BuyBooksTable">
<tr>
<th colspan="3">Books</th>
</tr>
<tr>
<th>Item</th>
<th>Price</th>
<th>Purchase Item</th>
</tr>
<tbody>
<tr>
<td>Alice</td>
<td>20</td>
<td>Purchase Item</td>
</tr>
<tr>
<td>Bob</td>
<td>15</td>
<td>Purchase Item</td>
</tr>
<tr>
<td>Carol</td>
<td>2</td>
<td>Purchase Item</td>
</tr>
</tbody>
</table>
I have the following code to create a left and right border when a row is selected in a table. I want the borders to only appear when the row is currently selected, and to disappear when it is not selected.
I attach a mock up:
function addRowHandlers() {
var table = document.getElementById("example");
var rows = table.getElementsByTagName("tr");
for (i = 0; i < rows.length; i++) {
var currentRow = table.rows[i];
var createClickHandler =
function(row) {
return function() {
var cell = row.getElementsByTagName("td")[0];
row.getElementsByTagName("td")[0].style.backgroundColor = "white";
row.firstElementChild.style.borderLeft = "black solid 2px";
row.lastElementChild.style.borderRight = "black solid 2px";
var id = cell.innerHTML;
alert("id:" + id);
};
};
currentRow.onclick = createClickHandler(currentRow);
}
}
window.onload = addRowHandlers();
tr td:first-child { border-left:2px solid transparent;}
tr td:last-child { border-right:2px solid transparent;}
<div>
<table id="example">
<tr>
<th>Firstname</th>
<th>Lastname</th>
<th>Age</th>
</tr>
<tr>
<td>Jill</td>
<td>Smith</td>
<td>50</td>
</tr>
<tr>
<td>Eve</td>
<td>Jackson</td>
<td>94</td>
</tr>
<tr>
<td>John</td>
<td>Doe</td>
<td>80</td>
</tr>
</table>
</div>
Use a class for the current selection styles ( I named it highlight) then on click remove this class from all rows with this
for (var i = 0; i < table.rows.length; i++) {
table.rows[i].classList.remove('highlight');
}
and then add it to the current row with row.className += "highlight"; check it out:
function addRowHandlers() {
var table = document.getElementById("example");
var rows = table.getElementsByTagName("tr");
for (i = 0; i < rows.length; i++) {
var currentRow = table.rows[i];
var createClickHandler =
function(row) {
return function() {
for (var i = 0; i < table.rows.length; i++) {
table.rows[i].classList.remove('highlight');
}
var cell = row.getElementsByTagName("td")[0];
row.getElementsByTagName("td")[0].style.backgroundColor = "white";
row.className += "highlight";
var id = cell.innerHTML;
};
};
currentRow.onclick = createClickHandler(currentRow);
}
}
window.onload = addRowHandlers();
tr:not(.highlight) td:first-child { border-left:2px solid transparent;}
tr:not(.highlight) td:last-child { border-right:2px solid transparent;}
tr.highlight td:first-child { border-left:2px solid black;}
tr.highlight td:last-child { border-right:2px solid black;}
<div>
<table id="example">
<tr>
<th>Firstname</th>
<th>Lastname</th>
<th>Age</th>
</tr>
<tr>
<td>Jill</td>
<td>Smith</td>
<td>50</td>
</tr>
<tr>
<td>Eve</td>
<td>Jackson</td>
<td>94</td>
</tr>
<tr>
<td>John</td>
<td>Doe</td>
<td>80</td>
</tr>
</table>
</div>
Here I tried a differenct approach with less code.
If you inspect from console, you'll see the change: click event adds the class to that row, and resets other rows' classes.
var mytable = document.getElementById("example");
var myrows = mytable.rows;
function giveStyle(el) {
Array.from(myrows).map(e => e.className = "");
el.className = "someclass";
}
.someclass {
/*something here */
}
<table id="example">
<tr>
<td>First</td>
<td>Last</td>
<td>Age</td>
</tr>
<tr onclick="giveStyle(this)">
<td>John</td>
<td>Doe</td>
<td>50</td>
</tr>
<tr onclick="giveStyle(this)">
<td>Alice</td>
<td>Wilsom</td>
<td>40</td>
</tr>
<tr onclick="giveStyle(this)">
<td>Otto</td>
<td>Weininger</td>
<td>25</td>
</tr>
</table>
Please use this function also :
function resetRowHandlers() {
var table = document.getElementById("example");
var rows = table.getElementsByTagName("tr");
for (i = 0; i < rows.length; i++) {
var row = table.rows[i];
row.getElementsByTagName("td")[0].style.backgroundColor = "none";
row.firstElementChild.style.borderLeft = "transparent solid 2px";
row.lastElementChild.style.borderRight = "transparent solid 2px";
}
}
Also call this function on click of row i.e. createClickHandler