JavaScript single input search multiple html table columns - javascript

I am using PHP and MySQL to build an HTML table. I am trying to use JavaScript to filter/search the table and only display the rows with the results I need. I want the JavaScript input to search multiple <td>s of the table. I was able to get this to work, but it is not going to be an elegant solution to put in place with larger tables.
I am sure there is a better way to choose what is being searched, but have not been able to find anything. Does anybody know a way for me to make this code more flexible for varying column width tables?
function myFunction() {
var input, filter, table, tr, td, i;
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")[0];
td1 = tr[i].getElementsByTagName("td")[1];
if (td+td1) {
if ((td.innerHTML.toUpperCase().indexOf(filter)+td1.innerHTML.toUpperCase().indexOf(filter)) > -2) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
}
}
<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Search" title="Type in anything">
<table id="myTable">
<tr class="header">
<th style="width:60%;">Name</th>
<th style="width:40%;">Country</th>
</tr>
<tr>
<td>North/South</td>
<td>UK</td>
</tr>
<tr>
<td>Paris specialites</td>
<td>France</td>
</tr>
</table>

There's a lot you can improve. Start by remembering to explicitly declare your variables, otherwise they become global.
This solution doesn't rely on any specific number of columns. It will work no matter how many there are.
See comments inline for more:
// Get DOM references just once:
var input = document.getElementById("myInput");
var table = document.getElementById("myTable");
// Do event binding in JavaScript, not HTML
input.addEventListener("keyup", filter);
input.addEventListener("search", filter);
// Get all rows, except the header and convert to array so .forEach() can be used to loop
var rows = Array.prototype.slice.call(table.querySelectorAll("tr:not(.header)"));
function filter() {
// Always trim user input
var filter = input.value.trim().toUpperCase();
// Loop the rows
rows.forEach(function(row) {
// You really don't need to know if the search criteria
// is in the first or second cell. You only need to know
// if it is in the row.
var data = "";
// Loop over all the cells in the current row and concatenate their text
Array.prototype.slice.call(row.getElementsByTagName("td")).forEach(function(r){
// Don't use .innerHTML unless there is HTML. Use textContent when there isn't.
data += r.textContent;
});
// Check the string for a match and show/hide row as needed
// Don't set individual styles. Add/remove classes instead
if(data.toUpperCase().indexOf(filter) > -1){
// show row
row.classList.remove("hidden");
} else {
// hide row
row.classList.add("hidden");
}
});
}
input[type=search]{
border-radius:10px;
outline:0;
padding:3px;
}
input[type=search]:focus{
box-shadow:0 0 4px blue;
}
.hidden { display:none; }
.leftHeader { width:60%; }
.rightHeader { width:40%; }
<!-- Use the actual "search" input type and don't do inline CSS or JavaScript -->
<input type="search" id="myInput" placeholder="Search" title="Type in anything">
<table id="myTable">
<tr class="header">
<th class="leftHeader">Name</th>
<th class="rightHeader">Country</th>
</tr>
<tr>
<td>North/South</td>
<td>UK</td>
</tr>
<tr>
<td>Paris specialites</td>
<td>France</td>
</tr>
</table>

All what you have to do is to get the td content and then match it with the search input.
function search(value) {
$('table tr').each(function () {
var content = $(this).find('td').text();
if (content.toUpperCase().includes(value.trim().toUpperCase())) {
$(this).show();
} else {
$(this).hide();
}
});
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!DOCTYPE html>
<html>
<body>
<input type="search" placeholder="Search..." id="search_account" onkeyup="search(this.value)">
<table>
<tr>
<td>Cell1</td>
<td>Cell2</td>
<td>Cell3</td>
</tr>
<tr>
<td>Cell4</td>
<td>Cell5</td>
<td>Cell6</td>
</tr>
</table>
</body>
</html>

Related

How do I keep buttons visible when searching table rows in javascript?

Basically where I have the 3 buttons 1, 2, and 3 in the second column first row if I type 3 the only button shows up is 3....removing buttons 1 and 2
for example if I'm looking for text with "2" in it it should still show
I want all buttons to stay regardless if they show up in the search or not...can this be achieved?
I have atleast 4 columns visible at all times and I want to search ONLY the text in the < TD > not the element text in the < TD > so radio buttons, buttons, check boxes....I want those to be immune from searches always show them as long as that particular row has the text snippet in one of the columns of that row just search the text in < TD >
Googling the right phrase has led me here because google assumes I want a checkbox to search a table....NO....I want a search to only focus on text not element text if that makes sense
Thanks
function myFunction() {
const input = document.getElementById("myInput");
const inputStr = input.value.toUpperCase();
const search_length = inputStr.length;
//alert(search_length);
document.querySelectorAll('#myTable tr:not(.header)').forEach((tr) => {
const anyMatch = [...tr.children]
.some(td => td.textContent.toUpperCase().includes(inputStr));
//fix the button issue here
if (anyMatch) tr.style.removeProperty('display');
else tr.style.display = 'none';
});
}
<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Type to search">
<table id="myTable" border="2">
<thead><tr>
<th>Col1</th>
<th>Col2</th>
</tr></thead>
<tbody>
<tr><td>2</td><td>
<table>
<tr><td>2<button type="button">1</button></td></tr>
<tr><td>5<button type="button">2</button></td></tr>
<tr><td>9<button type="button">3</button></td></tr>
</table></td></tr>
<tr><td>test4</td><td><button type="button">5</button></td></tr>
</tbody>
</table>
If you do not want to hide the sub table rows your selector needs to only touch the outside table.
function myFunction() {
const input = document.getElementById("myInput");
const inputStr = input.value.toUpperCase();
const search_length = inputStr.length;
//alert(search_length);
document.querySelectorAll('#myTable > tbody > tr:not(.header)').forEach((tr) => {
const anyMatch = [...tr.children]
.some(td => td.textContent.toUpperCase().includes(inputStr));
//fix the button issue here
if (anyMatch) tr.style.removeProperty('display');
else tr.style.display = 'none';
});
}
<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Type to search">
<table id="myTable" border="2">
<thead>
<tr>
<th>Col1</th>
<th>Col2</th>
</tr>
</thead>
<tbody>
<tr>
<td>2</td>
<td>
<table>
<tr>
<td>2<button type="button">1</button></td>
</tr>
<tr>
<td>5<button type="button">2</button></td>
</tr>
<tr>
<td>9<button type="button">3</button></td>
</tr>
</table>
</td>
</tr>
<tr>
<td>test4</td>
<td><button type="button">5</button></td>
</tr>
</tbody>
</table>

JavaScript Search Table by Index

I have a table with multiple columns (for this question I only made two columns) and I want the user to be able to search through a column by the index depending on an option that the user can select. I have working code, but in order to change the search option, I had to copy the function for each input.
How can I search by the index? If a user selects an option like (name), then the javascript function will change the index that it is searching to [0]. if the user selects (location), the function will change the index to [1] and search through that column.
Is this possible? Any help would be appreciated.
const searchName = document.getElementById('searchName');
const searchLoc = document.getElementById('searchLoc');
custSelect.addEventListener('click', () => {
if (custSelect.value == 'custname') {
searchName.style.display = 'block';
searchLoc.style.display = 'none';
} else {
searchName.style.display = 'none';
searchLoc.style.display = 'block';
}
});
// Search for customer, or search for location, index will change based on option selected.
function tableSearch(id, index) {
// Declare variables
var filter, input, table, tr, td, i;
input = document.getElementById(id);
filter = input.value.toUpperCase();
table = document.getElementById(id);
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")[0]; // index will change based on option selected.
if (td) {
if (td.innerHTML.toUpperCase().indexOf(filter) > -1) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
}
}
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
</head>
<body>
<div id="custDiv">
<div class="addBtns">
<input id="searchName" onkeyup="tableSearch('searchName','custList'[0])" type="text" placeholder="search name" />
<!-- this searches through the first index or [0] -->
<input id="searchLoc" onkeyup="tableSearch('searchLoc','custList'[1])" style="display: none;" type="text" placeholder="search location" />
<!-- this searches through the second index or [1] -->
<div id="custSelectDiv" style="width: 175px; height: 35px; max-height: 35px; margin: 0 auto;">
<select id="custSelect" style="position: absolute;">
<option value="custname">name</option> <!-- if user selects this, the corresponding input is displayed, which changes the index to search through -->
<option value="location">location</option> <!-- if user selects this, the corresponding input is displayed, which changes the index to search through -->
</select>
</div>
</div>
<table id="custListTop" contenteditable="false">
<tr>
<td style="border-top-left-radius: 5px;">Customers</td>
<td style="border-top-right-radius: 5px;">Main Location</td>
</tr>
</table>
<table id="custList" contenteditable="true">
<tr>
<td>josh</td>
<td>hawkins</td>
</tr>
<tr>
<td>hanna</td>
<td>big sandy</td>
</tr>
<tr>
<td>bonne</td>
<td>big sandy</td>
</tr>
<tr>
<td>thomas</td>
<td>big sandy</td>
</tr>
</table>
</div>
<script src="test.js"></script>
</body>
</html>
This should get you on track
var table = document.getElementById('tab'),
col = document.getElementById('col'),
val = document.getElementById('val');
col.max = table.rows[0].cells.length - 1;
function search() {
var regex = new RegExp(val.value || '', 'i');
for (var i = table.rows.length; i-- > 1;) {
if (regex.test(table.rows[i].cells[+col.value].innerHTML)) {
table.rows[i].style.display = 'table-row';
} else
table.rows[i].style.display = 'none';
}
}
table {
border-collapse: collapse;
}
table,
th,
td {
border: 1px solid;
}
<label for="col">Column :</label>
<input type="number" id="col" placeholder="column" onkeyup="search()" min="0" step="1" />
<br>
<label for="val">Find :</label>
<input type="text" id="val" placeholder="cell" onkeyup="search()" />
<table id="tab">
<tr>
<th>Customers</th>
<th>Main Location</th>
</tr>
<tr>
<td>josh</td>
<td>hawkins</td>
</tr>
<tr>
<td>hanna</td>
<td>big sandy</td>
</tr>
<tr>
<td>bonne</td>
<td>big sandy</td>
</tr>
<tr>
<td>thomas</td>
<td>big sandy</td>
</tr>
</table>
I think they are two simplier ways to do that research :
Use an object array to search what you need, reorganize it at each research and re-make your html table each time the table changes.
Or use dataTable, which is a very simple tool to sort table.

A table by specific columns content

I have a table that should eventually have 5 columns which I want to be able to sort though only the value of one column, "Name". This is what my function looks like so far:
function RenderResultsByName() {
//Declaration of variables
var nameInput, nameFilter, ul, li, a, i;
//Set the variables accorging to matching id's
//Name
nameInput = document.getElementById('nameInput');
nameFilter = nameInput.value.toUpperCase();
ul = document.getElementById("UL");
li = document.getElementsByTagName('tr');
console.log(li[0]);
//Loop trough items and hide those who don't match the query-->
for (i = 0; i < li.length; i++) {
a = li[i].getElementsByTagName("td")[0];
if (a.innerHTML.toUpperCase().indexOf(nameFilter) > -1) {
li[i].style.display = "";
}
else {
li[i].style.display = "none";
}
}
}
The HTML looks like this
<div class="row">
<div class="col-md-3">
<label>Namn: </label><br />
<input type="text" id="nameInput" onkeyup="RenderResultsByName()" placeholder="Sök efter namn..." /> <br /> <br />
</div>
</div>
<br /><br />
<table id="UL" class="table table-bordered">
<tr>
<th>Name</th>
<th>Yada</th>
<th>Yada</th>
<th>Yada</th>
<th>Yada</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>#item.visitor.FullName</td>
</tr>
}
</table>
I tried to apply a class "tdOfName" on all the 's in the Name column, but after that the sort stopped working because the a variable became undefined.
How would you solve this?
First, two things for your HTML code:
First a piece of advice, add thead and tbody to your tables to simplify jquery row selectors (and is a good practice, anyway).
You're creating 5 columns in the head row but only one in the rest. You have to add the rest or set a colspan.
<table id="UL" class="table table-bordered">
<thead>
<tr>
<th>Name</th>
<th>Yada</th>
<th>Yada</th>
<th>Yada</th>
<th>Yada</th>
</tr>
<thead>
<tbody>
#foreach (var item in Model) {
<tr>
<td>#item.visitor.FullName</td><td></td><td></td><td></td><td></td>
</tr>
}
<tbody>
</table>
Then, you say sort but your function is trying to show/hide rows attending at the input of the value. I can't see any sign of sorting. In case what you want is show/hide rows that has the input value in the first column, you can simplify it with this...
jQuery.expr[':'].icontains = function(a, i, m) {
return jQuery(a).text().toUpperCase().indexOf(m[3].toUpperCase()) >= 0;
};
$('input#nameInput').on('keyup',function() {
$('table#UL tbody tr').hide().filter(':has(td:first:icontains('+this.value+'))').show();
});
Here you have an fiddle example... https://fiddle.jshell.net/rigobauer/4rzf4wt7/
Is this what you're looking for?
I hope it helps.

Search bar that hides all elements until search

I am trying to make my search bar hide all of the elements until the user actually searches for them.`Heres a JSfiddel
<div id="search">
<form>
<input type="text" name="search" id="myInput" onkeyup="mFunction()"
placeholder="Search ?..">
</form>
<nav>
<table id="myTable">
<tr class="header">
<th style="width:500px;">Question</th>
</tr>
<tr>
<td onclick="window.location.href='#web'">What is the company email?</td>
</tr>
<tr>
<td onclick="window.location.href='#web'">Is the website currently under
development?</td>
</tr>
<tr>
<td onclick="window.location.href='#game'">Why are the games not working
online?</td>
</tr>
<tr>
<td onclick="window.location.href='#game'">What is the next game or games
that you are working on?</td>
</tr>
<tr>
<td onclick="window.location.href='#game'">Are you working on Modern Jewels
anymore?</td>
</tr>
<tr>
<td onclick="window.location.href='#game'">What are the controls for Modern
Jewels?</td>
</tr>
</table>
</div>
</nav>`
JavaScript/jQuery
function mFunction() {
// Declare variables
var input, filter, table, tr, td, i;
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")[0];
if (td) {
if (td.innerHTML.toUpperCase().indexOf(filter) > -1) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
}
}
Do you know how, it is for a FAQ page and I want the users to be able to search for the questions without a load of questions all in the search.
Thanks any help appreciated :D
Since you have all the search results in the table, you can just toogle with the entire table by using jquerys .hide() and .show() animations.
to hide the table until user searches hide the table by using .hide()
$("#myTable").hide();
you could done this, by checking on keyup in your search. if the value is empty, then you can hide all of your table, else, you can show td in table which contains your search
$('table').hide();
$('#myInput').on("keyup", function(){
var searchVal = $('#myInput').val();
if(searchVal == ""){
$('table').hide();
}
else{
$('table').show();
$('table tr td').show();
$('table tr td:not(:contains("' + searchVal + '"))').hide();
}
});
demo : https://jsfiddle.net/p90uwdg7/
but this search is case sensitive, if you want to overcome this case sensitive, you need to overwrite the contains function
jQuery.expr[':'].contains = function(a, index, obj) {
return jQuery(a).text().toUpperCase()
.indexOf(obj[3].toUpperCase()) >= 0;
};
demo : https://jsfiddle.net/p90uwdg7/1/

How can I hide a table until filtered/input entered in search

I'm new to web developing but catching on fairly quickly. I'm developing a wiki page for my company and I have a filter table built but I want to hide the table until the filter function is applied when a user enters their search text. So this way it only shows the text input box and then when they type in their search the table results will THEN show.
I'm using this Javascript for the filtering:
function ContactsearchFX() {
var input, filter, table, tr, td, i;
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")[0];
if (td) {
if (td.innerHTML.toUpperCase().indexOf(filter) > -1) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
}
}
on a basic search table with this html code:
<input type="text" id="myInput" onkeyup="ContactsearchFX()" placeholder="Search for names..">
<table id="myTable">
<tr class="header">
<th style="width:60%;">Name</th>
<th style="width:40%;">Number</th>
</tr>
<tr>
<td>contact</td>
<td>number</td>
</tr>
<tr>
<td>contact</td>
<td>number</td>
</tr>
<tr>
<td>contact</td>
<td>number</td>
</tr>
....and so on.
window.onload = function() {
var rows = document.querySelectorAll('tr:not(.header)');
for (var i = 0; i < rows.length; i++) {
rows[i].style.display = 'none';
}
}
function ContactsearchFX() {
var input, filter, table, tr, td, i;
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")[0];
if (td) {
if (td.innerHTML.toUpperCase().indexOf(filter) > -1) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
}
var rows = document.querySelectorAll('tr:not(.header)');
if (input.value.length == 0) {
for (var i = 0; i < rows.length; i++) {
rows[i].style.display = 'none';
}
}
}
<input type="text" id="myInput" onkeyup="ContactsearchFX()" placeholder="Search for names..">
<table id="myTable">
<tr class="header">
<th style="width:60%;">Name</th>
<th style="width:40%;">Number</th>
</tr>
<tr>
<td>test 1</td>
<td>number</td>
</tr>
<tr>
<td>test 2</td>
<td>number</td>
</tr>
<tr>
<td>test 3</td>
<td>number</td>
</tr>
This seems to do the trick! On the load of the window, it loops through all the table rows which do now have the class of header. So your header, is always visible.
Then as your code originally did, it goes through the table and filters out the ones that are matching.
After this, I just added in another loop which then sets the rows back to display: none if there is nothing that is in the input box.
Hope this is what you were looking for.
You could give the table default styles that hide it so when it renders, its default state will be hidden.
<input type="text" id="myInput" onkeyup="ContactsearchFX()" placeholder="Search for names..">
<table id="myTable" style="display:none;">
<tr class="header">
<th style="width:60%;">Name</th>
<th style="width:40%;">Number</th>
</tr>
<tr>
<td>contact</td>
<td>number</td>
</tr>
<tr>
<td>contact</td>
<td>number</td>
</tr>
<tr>
<td>contact</td>
<td>number</td>
</tr>
I would suggest running the ContactsearchFX function on page load:
document.addEventListener('DOMContentLoaded', ContactsearchFX);
... and requiring that filter is not the empty string in the condition for displaying a row.
This has one particular advantage: some browsers remember the last text that was entered in the input box, and fill that text automatically again on page load. With this solution, the corresponding table rows will be filtered immediately.
For a more responsive effect, I would remove the onkeyup="ContactsearchFX()" HTML attribute, and instead add the following JavaScript:
document.addEventListener('DOMContentLoaded', function () {
document.getElementById('myInput').addEventListener('input', ContactsearchFX);
});
Also consider using the rows and cells collections instead of getElementsByTagName
Probably you want to keep the header row out of the filtering process, and so your loop should start at 1 instead of 0.
document.addEventListener('DOMContentLoaded', function () {
ContactsearchFX();
document.getElementById('myInput').addEventListener('input', ContactsearchFX);
});
function ContactsearchFX() {
var input, filter, table, tr, td, i;
input = document.getElementById("myInput");
filter = input.value.toUpperCase();
table = document.getElementById("myTable");
tr = table.rows;
for (i = 1; i < tr.length; i++) {
td = tr[i].cells[0];
if (td) {
tr[i].style.display = filter && td.textContent.toUpperCase().indexOf(filter) > -1
? "" : "none";
}
}
}
<input type="text" id="myInput" placeholder="Search for names..">
<table id="myTable">
<tr class="header">
<th style="width:60%;">Name</th>
<th style="width:40%;">Number</th>
</tr>
<tr>
<td>test 1</td>
<td>number</td>
</tr>
<tr>
<td>test 2</td>
<td>number</td>
</tr>
<tr>
<td>test 3</td>
<td>number</td>
</tr>
</table>

Categories