Javascript match/search table for results - total beginner - javascript

I am admittedly very inexperienced, but I'm trying to enhance the workflow at my company. I'm using the code from here to create internal site to search for current part numbers. My employees are searching by description, but the javascript included in the example searches by exact input instead of individual words.
For example, using the example code on the site, I would like a search for "Trading Island" to return the same result as "Island Trading". I know this is possible, but can't figure out how to make it work.
<!DOCTYPE html>
<html>
<head>
<style>
* {
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;
}
</style>
</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>
<script>
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];
if (td) {
if (td.innerHTML.toUpperCase().indexOf(filter) > -1) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
}
}
</script>
</body>
</html>

When searching for word matches, it's best to place the search string
into an array and the cell contents to be searched into an array.
Then you can easily use the Array.prototype.every() or the Array.prototype.some() methods to see if all or some of the search words are present in the cell.
See my comments inline below for additional details.
// Get a reference to the input
var searchElement = document.getElementById("myInput");
// Hook element up to event handler:
searchElement.addEventListener("keyup", search);
// Event handler:
function search(){
// Now, break the search input into an array of words by splitting the string where
// there are spaces (regular expression used here to locate the strings).
// Also, note that strings are case-sensitive, so we are taking the input and
// forcing it to lower case and we'll match by lower case later.
var searchWords = searchElement.value.toLowerCase().split(/\s+/);
// Test to see the individual words
//console.clear();
//console.log(searchWords);
// Now you have to have some content to search against.
// So, we'll get all the cells, which will be our data source:
var theCells = document.querySelectorAll("td");
// Loop over each cell
theCells.forEach(function(cell){
// Reset any previous cell matches
cell.style.backgroundColor = "inherit";
// Get the words in the cell as an array (note: we are forcing lower
// case again here to match lower case against lower case
var cellWords = cell.textContent.toLowerCase().split(/\s+/);
// See if the cell contains all of the search words (You can substitute
// "some" for "every" to just see if the cell contains some of the search words
var result = cellWords.every(elem => searchWords.indexOf(elem) > -1);
// every and some return a boolean letting you know if your condition was met:
if(result){
console.clear();
console.log("Match found in: " + cell.textContent);
cell.style.backgroundColor = "#ff0";
}
});
}
<input type="text" id="myInput" 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>

Related

Create a button with a specific value to use this JS function

I've been searching for this solution for quite some time, although I've been trying to find solutions in anything but JS (since I'm very unfamiliar with it).
I've stripped down some code so I can implement it.
Currently it has a search function which can filter based on the input in text you put in, but I'd like to create a link with preformatted text to use the same function.
So for instance, if I'd like to filter on "IS" without typing it, that there is a link/button one can use that uses the same function and give the same result. I can only find other JS examples that don't filter based on the input but only on specific criteria which, if it doesn't match exactly, returns without the other results.
This is the stripped code:
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++) {
td = tr[i].getElementsByTagName("td")[0];
if (td) {
txtValue = td.textContent || td.innerText;
if (txtValue.toUpperCase().indexOf(filter) > -1) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
}
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
</style>
</head>
<body>
<table id="myTable">
<tr>
<th>Name</th>
<th>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>
<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Search for names.." title="Type in a name">
</body>
</html>
You may have buttons next to the input for filtering the list. Each of them will call a common function filterBy(value) that will automatically populate the input text with the passed argument and will trigger its keyup event.
Here's a demo:
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++) {
td = tr[i].getElementsByTagName("td")[0];
if (td) {
txtValue = td.textContent || td.innerText;
if (txtValue.toUpperCase().indexOf(filter) > -1) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
}
}
function filterBy(value){
const target = document.querySelector('#myInput');
target.value = value;
target.dispatchEvent(new Event('keyup'));
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
</style>
</head>
<body>
<table id="myTable">
<tr>
<th>Name</th>
<th>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>
<div class="filter-container">
<input
type="text"
id="myInput"
onkeyup="myFunction()"
placeholder="Search for names.."
title="Type in a name">
<button type="button" onclick="filterBy('IS');">IS</button>
</div>
</body>
</html>
One approach – with explanatory comments in the code – is below:
// to save typing, I cached a reference to the document element:
const D = document,
// and created utility functions to reduce the amount of typing of 'document.querySelector...',
// these work as simple aliases for the querySelector(All) functions, though getAll() does return
// an Array instead of a NodeList, this may break expectations:
get = (selector, context = D) => context.querySelector(selector),
getAll = (selector, context = D) => [...context.querySelectorAll(selector)],
// again, to reduce typing document.createElement(...):
create = (tag) => D.createElement(tag),
// named function to create the tag-cloud of <button> elements with which you want to filter
// the <table>; this function accepts an opts Object to be passed in:
createTagCloud = (opts = {}) => {
// the default settings of the function:
let settings = {
// the element from which the tags will be formed from its contents:
tagSource: get('table tbody'),
// the class-name to add to the element containing the tag-cloud:
wrapperClass: 'tagCloud',
// the first required argument:
// this argument must reference an existing element-node in the document, which will
// contain the tag-cloud:
outputNode: null,
// the final required argument:
// this argument takes a function that is to be called when clicking on the created
// tag <button> elements:
execute: null,
},
// creating a <button> element:
button = create('button'),
// creating a document-fragment:
fragment = D.createDocumentFragment(),
// defining two variables for later use:
wrapper, clone;
// using the Object.keys() method to return an Array of the keys of the opts Object (which
// requires a minimum of two properties), and iterating over that Array using
// Array.prototype.forEach():
Object.keys(opts).forEach(
// using an Arrow function, which passes one argument (a reference to the current key
// of the Array of keys over which we're iterating) into the function body; in the
// body of the function we're updating the property of the settings Object to be
// equal to the property-value of the opts Object:
(key) => settings[key] = opts[key]
);
// if we don't have a
if (!settings.outputNode) {
// here we log a message to the console (I chose not to throw an Error because I didn't want to
// completely break things):
console.log(`%c Error: %c "outputNode" must be passed to the function, and specify a parent element into which the tag-cloud is to be inserted.`, "color: black; background-color: red; border-radius: 5px; font-weight: bold;", "all: unset;")
return false;
}
// passing a value to the wrapper variable, so that it becomes a reference to the
// DOM element-node which will hold the tag-cloud:
wrapper = settings.outputNode;
// if there is no settings.execute property-value:
if (!settings.execute) {
// we log the following message to the console:
console.log(`%c Error: %c "execute" must specify a function to call in order to perform a search using the created tags..`, "color: black; background-color: red; border-radius: 5px; font-weight: bold;", "all: unset;")
}
// here we retrieve the text-content of the element which will serve as the 'haystack' to be searched, trim
// leading/trailing white-space from that string of text and then split it on a sequence of one or more
// white-spaces using String.prototpe.split() with a regular expression:
let words = settings.tagSource.textContent.trim().split(/\s+/);
// we iterate over the Array of words, using Array.prototype.forEach():
words.forEach(
// with an Arrow function that passes in a reference to the current word of the Array
// of words over which we're iterating:
(word) => {
// we clone the <button> we created earlier, along with any descendants:
clone = button.cloneNode(true);
// we bind the named function - the property-value of the 'settings.execute' property that
// was passed into the function - as the event-handler for the 'click' event:
clone.addEventListener('click', settings.execute);
// we set the value-property of the cloned <button>, and its text-content, to
// the curent word:
clone.value = word;
clone.textContent = word;
// we then append that cloned <button> to the document-fragment:
fragment.append(clone);
});
// if a class-name was passed in to be assigned to the wrapper element:
if (settings.wrapperClass) {
// we use the Element.classList API to add that class:
wrapper.classList.add(settings.wrapperClass);
}
// here we append the document-fragment to the wrapper:
wrapper.append(fragment);
},
// the named function to handle the filtering and toggling of the <tr> elements
// of the <table>; this takes on argument passed automatically from the later
// use of the EventTarget.addEventListener() function:
find = (evt) => {
// we retrieve the value of the <button> that was fired:
let needle = evt.currentTarget.value,
// and we retrieve the <tr> elements from the <tbody> of the <table>:
haystack = getAll('table tbody tr');
// we use Array.prototype.forEach() to iterate over those <tr> elements:
haystack.forEach(
// passing a reference to the current <tr> to the function, in which
// we again use the Element.classList API to toggle the 'hidden' class
// on the current <tr> ('row').
// if the current row does *not* include the current word ('needle'),
// we invert the false (from String.prototype.includes()) using the
// NOT operator ('!') which means the assessment becomes truthy which
// in turn means that the class will be added to those elements which
// do not contain the current word; this causes them to be hidden.
// If the current <tr> does contain the 'needle', then the true (from
// String.prototype.includes()) is inverted to false, so the class-name
// is *not* added:
(row) => row.classList.toggle('hidden', !row.textContent.includes(needle))
)
};
// calling the function:
createTagCloud({
// passing in the required arguments, first the outputNode,
// which is the <div> following the <table>:
outputNode: get('table + div'),
// and a reference to the function to be called when the
// tags are clicked:
execute: find,
});
*,
::before,
::after {
box-sizing: border-box;
font-family: Roboto, Montserrat, system-ui;
font-size: 16px;
font-weight: 400;
line-height: 1.4;
margin: 0;
padding: 0;
}
main {
border: 1px solid #000;
display: flex;
margin-block: 1em;
margin-inline: auto;
padding: 0.5em;
width: 70vw;
}
main>* {
border: 1px solid currentColor;
flex-basis: 50%;
flex-grow: 1;
}
table {
border-collapse: collapse;
}
thead th {
border-block-end: 0.1em solid currentColor;
}
tbody tr {
background-color: #fff;
}
tbody tr:nth-child(odd) {
background-color: lightblue;
}
td {
padding-block: 0.25em;
padding-inline: 0.5em;
}
button {
padding-block: 0.25em;
padding-inline: 0.5em;
}
.tagCloud {
display: flex;
align-content: start;
flex-flow: row wrap;
gap: 0.5em;
justify-content: space-between;
padding: 0.5em;
}
.hidden {
opacity: 0.2;
}
<!-- wrapped all content in a <main> tag to identify the main content of the site: -->
<main>
<table id="myTable">
<!-- used a <thead> element to wrap the header rows that contain the <th> elements: -->
<thead>
<tr>
<th>Name</th>
<th>Country</th>
</tr>
</thead>
<!-- using a <tbody> to wrap the content of the <table> to make it easier to create the
tag-cloud: -->
<tbody>
<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>
</tbody>
</table>
<!-- added a <div> to contain the created tag-cloud: -->
<div></div>
</main>
JS Fiddle demo.
References:
Array.prototype.forEach().
console API.
document.createElement().
document.createDocumentFragment().
document.querySelector().
document.querySelectorAll().
Element.append().
Element.classList API.
Element.querySelector().
Element.querySelectorAll().
Event.currentTarget.
EventTarget.addEventListener().
Node.cloneNode().
Node.textContent.
Object.keys().
String.prototype.includes().
String.prototype.split().
String.prototype.trim().

how to use bootstrap filter for searching a name by first letter

I am using bootstrap filter for searching. But,for example when I type 'n' it shows all the name having 'n' like nathan, arjan . I don't want that.I want like this : if i type 'n' it will show only the names which starts with 'n' like nathaan,narima.
my blade.php code here:
<input class="form-control" id="myInput" type="text" placeholder="Search..">
<tbody id="myTable">
<tr>
<td>John</td>
</tr>
<tr>
<td>Anja</td>
</tr>
</tbody>
my script part here
<script>
$(document).ready(function(){
$("#myInput").on("keyup", function() {
var value = $(this).val().toLowerCase();
$("#myTable tr").filter(function() {
$(this).toggle($(this).text().toLowerCase().indexOf(value) > -1)
});
});
});
</script>
There is a method called startsWith that you can use. The documentation can be found at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith
<script>
$(document).ready(function(){
$("#myInput").on("keyup", function() {
var value = $(this).val().toLowerCase();
$("#myTable tr").filter(function() {
$(this).toggle($(this).text().toLowerCase().startsWith(value))
});
});
});
</script>
you can change the method if you want.
$("#myInput").bind("keyup", function() {
var text = $(this).val().toLowerCase();
var items = $("tr td");
//first, hide all:
items.parent().hide();
//show only those matching user input:
items.filter(function () {
return $(this).text().toLowerCase().indexOf(text) == 0;
}).parent().show();
});
Another way would be using RegExp:
$(document).ready(function() {
$("#myInput").on("keyup", function() {
var value = $(this).val().toLowerCase();
$("#myTable tr").filter(function() {
/* $(this).toggle($(this).text().toLowerCase().indexOf(value) > -1) */
const searchRegEx = new RegExp(`^${value}`, 'i');
$(this).toggle(searchRegEx.test($(this).text().trim()));
});
});
});
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"></script>
<input class="form-control" id="myInput" type="text" placeholder="Search..">
<table class="table table-bordered">
<tbody id="myTable">
<tr>
<td>John</td>
</tr>
<tr>
<td>Anja</td>
</tr>
</tbody>
</table>
Using .charAt(0) for result set to be filtered with first character match
Basic example from w3schools modified
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
* {
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;
}
</style>
</head>
<body>
<h2>My Customers</h2>
<input type="text" id="myInput" onkeyup="filterBy()" placeholder="Search..." 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>Marimba</td>
<td>Something</td>
</tr>
<tr>
<td>Marimba</td>
<td>Something</td>
</tr>
<tr>
<td>North/South</td>
<td>UK</td>
</tr>
<tr>
<td>Paris specialites</td>
<td>France</td>
</tr>
</table>
<script>
function filterBy() {
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++) {
td = tr[i].getElementsByTagName("td")[0];
if (td) {
txtValue = td.textContent || td.innerText;
if (txtValue.toUpperCase().indexOf(filter) > -1) {
if (txtValue.toUpperCase().charAt(0) == filter.charAt(0)) {
tr[i].style.display = "";
}
} else {
tr[i].style.display = "none";
}
if(filter.length == 0)
{
tr[i].style.display = "";
}
}
}
}
</script>
</body>
</html>

Individual column searching (text inputs)

I'm trying to add an individual search box for each table column without success.
What should be added to code below in order to make it work?
Currently my code contains a single search box for first column only.
Please run snippet to get full details.
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++) {
td = tr[i].getElementsByTagName("td")[0];
if (td) {
txtValue = td.textContent || td.innerText;
if (txtValue.toUpperCase().indexOf(filter) > -1) {
tr[i].style.display = "";
} else {
tr[i].style.display = "none";
}
}
}
}
p.a {
white-space: nowrap;
}
h2 {
text-align: center;
font-family: Helvetica, Arial, sans-serif;
}
table {
margin-left: auto;
margin-right: auto;
}
table, th, td {
border: 1px solid black;
border-collapse: collapse;
}
th, td {
padding: 5px;
text-align: left;
font-family: Helvetica, Arial, sans-serif;
font-size: 90%;
white-space:nowrap;
}
table tbody tr:hover {
background-color: #dddddd;
}
.wide {
width: 90%;
}
<h2> Title here </h2>
<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Search for names.." title="Type in a name"><table border="1" class="dataframe wide" id="myTable">
<thead>
<tr style="text-align: right;">
<th></th>
<th>KEY</th>
<th>DEVREVSTEP</th>
<th>WW32</th>
<th>WW33</th>
<th>WW34</th>
<th>WW35</th>
<th>WW36</th>
<th>WW37</th>
<th>WW38</th>
<th>WW39</th>
<th>WW40</th>
<th>Rule</th>
<th>LINK</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>First</td>
<td>A</td>
<td>-0.64</td>
<td>6.47</td>
<td>23.14</td>
<td>3.51</td>
<td>0.13</td>
<td>-0.41</td>
<td>-0.59</td>
<td>-0.31</td>
<td>33.13</td>
<td>A</td>
<td>Google.com</td>
</tr>
<tr>
<th>1</th>
<td>Second</td>
<td>B</td>
<td>-18.04</td>
<td>-18.42</td>
<td>-17.44</td>
<td>-16.35</td>
<td>-19.06</td>
<td>-17.49</td>
<td>-18.62</td>
<td>-17.92</td>
<td>-18.23</td>
<td>C</td>
<td>Amazon.com</td>
</tr>
<tr>
<th>2</th>
<td>Third</td>
<td>C</td>
<td>NaN</td>
<td>NaN</td>
<td>-0.59</td>
<td>2.25</td>
<td>-0.33</td>
<td>0.55</td>
<td>-0.53</td>
<td>8.96</td>
<td>17.53</td>
<td>B</td>
<td>Ebay.com</td>
</tr>
<tr>
<th>3</th>
<td>Fourth</td>
<td>A</td>
<td>-0.18</td>
<td>3.25</td>
<td>7.63</td>
<td>1.90</td>
<td>-0.19</td>
<td>0.41</td>
<td>0.15</td>
<td>0.20</td>
<td>17.31</td>
<td>A</td>
<td>Yahoo.com</td>
</tr>
<tr>
<th>4</th>
<td>Fourth</td>
<td>A</td>
<td>0.24</td>
<td>-3.25</td>
<td>-6.42</td>
<td>-1.51</td>
<td>0.60</td>
<td>-0.01</td>
<td>0.25</td>
<td>-0.02</td>
<td>-15.13</td>
<td>A</td>
<td>MSN.com</td>
</tr>
<tr>
<th>5</th>
<td>First</td>
<td>D</td>
<td>NaN</td>
<td>NaN</td>
<td>NaN</td>
<td>NaN</td>
<td>5.06</td>
<td>NaN</td>
<td>1.27</td>
<td>-0.56</td>
<td>13.24</td>
<td>A</td>
<td>Google.com</td>
</tr>
</tbody>
</table>
If you want to show only rows that are a match for all entered filter values - then you best loop over all the input fields on each change, that is easiest to handle.
I inserted input fields into the table header cells here, and then simply select them using getElementsByTagName - you can change that to a different position and / or using a different method to select them (f.e. by class maybe), it might need some slight adaptations then.
Notice how in both loops I start with the index 1 here, not 0 - to ignore the first table row in the i loop (because the header row should not disappear; could be done differently by selecting only the rows in the tbody to begin with), and to ignore the first cell in the j loop. And since the number of input fields is one less than the number of cells per row, I access the input using index j - 1, got get the one corresponding to the cell index.
This probably leaves room for refinements in several places, but should be enough to illustrate the basic principle.
function myFunction() {
var inputs, table, tr, i, j, inputValue, txtValue, showRow;
inputs = document.getElementsByTagName("input");
table = document.getElementById("myTable");
tr = table.getElementsByTagName("tr");
for (i = 1; i < tr.length; i++) {
showRow = true;
for (j = 1; j < tr[i].cells.length; j++) {
inputValue = inputs[j - 1].value
txtValue = tr[i].cells[j].textContent || tr[i].cells[j].innerText;
if (inputValue != "" && txtValue.toUpperCase().indexOf(inputValue.toUpperCase()) == -1) {
showRow = false;
break;
}
}
tr[i].style.display = showRow ? "" : "none";
}
}
p.a {
white-space: nowrap;
}
h2 {
text-align: center;
font-family: Helvetica, Arial, sans-serif;
}
table {
margin-left: auto;
margin-right: auto;
}
table,
th,
td {
border: 1px solid black;
border-collapse: collapse;
}
th,
td {
padding: 5px;
text-align: left;
font-family: Helvetica, Arial, sans-serif;
font-size: 90%;
white-space: nowrap;
}
table tbody tr:hover {
background-color: #dddddd;
}
.wide {
width: 90%;
}
<h2> Title here </h2>
<table border="1" class="dataframe wide" id="myTable">
<thead>
<tr style="text-align: right;">
<th></th>
<th><input type="text" onkeyup="myFunction()"><br>KEY</th>
<th><input type="text" onkeyup="myFunction()"><br>DEVREVSTEP</th>
<th><input type="text" onkeyup="myFunction()"><br>WW32</th>
<th><input type="text" onkeyup="myFunction()"><br>WW33</th>
<th><input type="text" onkeyup="myFunction()"><br>WW34</th>
<th><input type="text" onkeyup="myFunction()"><br>WW35</th>
<th><input type="text" onkeyup="myFunction()"><br>WW36</th>
<th><input type="text" onkeyup="myFunction()"><br>WW37</th>
<th><input type="text" onkeyup="myFunction()"><br>WW38</th>
<th><input type="text" onkeyup="myFunction()"><br>WW39</th>
<th><input type="text" onkeyup="myFunction()"><br>WW40</th>
<th><input type="text" onkeyup="myFunction()"><br>Rule</th>
<th><input type="text" onkeyup="myFunction()"><br>LINK</th>
</tr>
</thead>
<tbody>
<tr>
<th>0</th>
<td>First</td>
<td>A</td>
<td>-0.64</td>
<td>6.47</td>
<td>23.14</td>
<td>3.51</td>
<td>0.13</td>
<td>-0.41</td>
<td>-0.59</td>
<td>-0.31</td>
<td>33.13</td>
<td>A</td>
<td>Google.com</td>
</tr>
<tr>
<th>1</th>
<td>Second</td>
<td>B</td>
<td>-18.04</td>
<td>-18.42</td>
<td>-17.44</td>
<td>-16.35</td>
<td>-19.06</td>
<td>-17.49</td>
<td>-18.62</td>
<td>-17.92</td>
<td>-18.23</td>
<td>C</td>
<td>Amazon.com</td>
</tr>
<tr>
<th>2</th>
<td>Third</td>
<td>C</td>
<td>NaN</td>
<td>NaN</td>
<td>-0.59</td>
<td>2.25</td>
<td>-0.33</td>
<td>0.55</td>
<td>-0.53</td>
<td>8.96</td>
<td>17.53</td>
<td>B</td>
<td>Ebay.com</td>
</tr>
<tr>
<th>3</th>
<td>Fourth</td>
<td>A</td>
<td>-0.18</td>
<td>3.25</td>
<td>7.63</td>
<td>1.90</td>
<td>-0.19</td>
<td>0.41</td>
<td>0.15</td>
<td>0.20</td>
<td>17.31</td>
<td>A</td>
<td>Yahoo.com</td>
</tr>
<tr>
<th>4</th>
<td>Fourth</td>
<td>A</td>
<td>0.24</td>
<td>-3.25</td>
<td>-6.42</td>
<td>-1.51</td>
<td>0.60</td>
<td>-0.01</td>
<td>0.25</td>
<td>-0.02</td>
<td>-15.13</td>
<td>A</td>
<td>MSN.com</td>
</tr>
<tr>
<th>5</th>
<td>First</td>
<td>D</td>
<td>NaN</td>
<td>NaN</td>
<td>NaN</td>
<td>NaN</td>
<td>5.06</td>
<td>NaN</td>
<td>1.27</td>
<td>-0.56</td>
<td>13.24</td>
<td>A</td>
<td>Google.com</td>
</tr>
</tbody>
</table>

Nth child in table not working Javascript

The td:nth-child('n') is not working over in my table it gives null in the log Where as it is working when i use children[n] it is a simple function for searching
I couldn't find the reason why it is giving out a null.. Here is the code
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Table Searching</title>
<style>
th{
font-weight: bolder;
}
table, th, td{
font-size: 20px;
border: 2px solid black;
border-collapse: collapse;
}
</style>
</head>
<body>
<input type="text" name="search">
<button class="s" onclick="Search()">Search by Name</button>
<button class="s" onclick="Search()">Search by Country</button>
<button class="s" onclick="Search()">Search by Pet</button>
<table>
<tr>
<th>Name</th>
<th>Country</th>
<th>Pet</th>
</tr>
<tr>
<td>Abhi</td>
<td>Canada</td>
<td>koala</td>
</tr>
<tr>
<td>Riya</td>
<td>France</td>
<td>Parrot</td>
</tr>
<tr>
<td>Sid</td>
<td>UK</td>
<td>Pig</td>
</tr>
<tr>
<td>Kritika</td>
<td>Germany</td>
<td>Cat</td>
</tr>
<tr>
<td>Kartik</td>
<td>China</td>
<td>Frog</td>
</tr>
<tr>
<td>Radhika</td>
<td>India</td>
<td>Dog</td>
</tr>
</table>
<script>
var input=document.getElementsByName("search")[0];
var s=document.getElementsByClassName("s");
var n=0;
function Search(){
for (var j=0; j<s.length; j++)
{
console.log("element");
console.log(s[j]);
console.log("target");
console.log(event.target);
if(s[j]==event.target){
n=j;
console.log(n);
}
}
var val= input.value;
var a=document.querySelectorAll("table > tbody > tr");
console.log(a);
for(var i =0; i<a.length; i++)
{
var d = a[i].querySelector('td:nth-child("+n+")');
console.log(d);
if(d.innerHTML.toLowerCase()==val.toLowerCase()){
a[i].style.display="";
}
else
{
a[i].style.display="none";
}
}
}
</script>
</body>
</html>
Here are the three reasons why you are giving out null in your code:
First, as stated by Satpal, this code 'td:nth-child("+n+")' will not replace n by its value. It's like writing td:nth-child("+n+") in css.
The solution for this is to write: 'td:nth-child(' + n + ')'. You then concatenate the value of n with the rest of the string
The value of n is an index in a array, so it starts at 0 and ends at array.length - 1. The problem is that the nth-child selector actually selects the nth-child (brilliant naming), so if n is 0 (in the case of searching by name), you'll try to select the 0th-child, wihich doesn't exist... You then have to write: 'td:nth-child(' + (n + 1) + ')' or change the definition of n
You have no <tbody> tag in your HTML. Which means that all the content of the table will be wrapped in a tbody and your selector document.querySelectorAll("table > tbody > tr")will also selects the header of your table. To avoid that, change your HTML accordingly.
Something like that:
<table>
<thead>
<tr>
<th>Name</th>
<th>Country</th>
<th>Pet</th>
</tr>
</thead>
<tbody>
<tr>
<td>Abhi</td>
<td>Canada</td>
<td>koala</td>
</tr>
<tr>
<td>Riya</td>
<td>France</td>
<td>Parrot</td>
</tr>
<tr>
<td>Sid</td>
<td>UK</td>
<td>Pig</td>
</tr>
<tr>
<td>Kritika</td>
<td>Germany</td>
<td>Cat</td>
</tr>
<tr>
<td>Kartik</td>
<td>China</td>
<td>Frog</td>
</tr>
<tr>
<td>Radhika</td>
<td>India</td>
<td>Dog</td>
</tr>
</tbody>
</table>
Here is a jsfiddle where the search works fine: https://jsfiddle.net/n23685b6/1/
Hope this helps!
scrollToNthChild = (): * => {
var tableBody = document.getElementById('event-table-body');
var tableRows = tableBody.getElementsByTagName('tr');
let targetElement = tableRows[7];
targetElement.scrollIntoView();
}

JS Sortable Tables with linked rows?

Okay, I have a table. In this table I have a whole bunch of columns, and I would like to use a Sortable Tables javascript so that the user can sort the table as they wish. There are many such JS scripts available (ie: http://tablesorter.com/docs/)
However, the problem I have is that for each row of my table that I want sorted, there is a colspan="4" row right below it that I dont want sorted. In fact, I want these rows linked directly to the row above them so that when those rows get sorted, the 4-span row below it sticks with it.
Is something like this possible?
table {
border: 1px black solid;
width: 100%;
}
thead {
background-color: lightgrey;
text-align: left;
}
.notes {
text-align: right;
}
<table>
<thead>
<tr>
<th>Command</th>
<th>DMG</th>
<th>EXE</th>
<th>TOT</th>
</tr>
</thead>
<tbody>
<tr>
<td>Jouho Touken</td>
<td>19</td>
<td>17</td>
<td>42</td>
</tr>
<tr>
<td colspan="4" class="notes">Opponent crouching (H: Stagger)</td>
</tr>
<tr>
<td>Chouyoushu</td>
<td>25</td>
<td>18</td>
<td>46</td>
</tr>
<tr>
<td colspan="4" class="notes">Damage varies due to distance (25-40)</td>
</tr>
<tr>
<td>Tetsuzankou</td>
<td>40</td>
<td>19</td>
<td>75</td>
</tr>
<tr>
<td colspan="4" class="notes">Super Replay; Damage varies due to distance: 40-80</td>
</tr>
</tbody>
</table>
Here is an example of how you could do this.
Make an array of all rows in the <tbody>.
Group it into pairs. [{data, note}, ...]
Sort by a given sorting function
Flatten back into an array of table rows.
empty the <tbody> tag
Insert into the <tbody> tag everything in the sorted table rows array.
var tableBody = document.querySelector('tbody')
var tableRows = Array
.from(document.querySelectorAll('tbody > tr'))
var notesAndData = []
/* Group elements into
[
{data: <tr>, note: <tr>},
...
]
*/
for(var i = 1; i < tableRows.length; i += 2) {
notesAndData.push({
data: tableRows[i-1],
note: tableRows[i]
})
}
function flatten(arr) {
return arr.reduce(function(acc, curr) {
acc.push(curr.data)
acc.push(curr.note)
return acc
}, [])
}
function repopulateTable(arr) {
tableBody.innerHTML = ''
arr.forEach(function(element) {
tableBody.appendChild(element)
})
}
function sortTable(sortingFunc) {
/* Spread the notesAndData into a new array in
order to not modify it. This syntax is es6 */
var sorted = [...notesAndData].sort(sortingFunc)
repopulateTable(flatten(sorted))
}
function sortByDmg(ascending) {
return function(a, b) {
var aDmg = parseInt(a.data.children[1].textContent)
var bDmg = parseInt(b.data.children[1].textContent)
if (aDmg < bDmg) return ascending ? 1 : -1
return ascending ? 1 : -1
}
}
document
.querySelector('.dmgSort')
.addEventListener('click', function() {
sortTable(sortByDmg(true))
})
table {
border: 1px black solid;
width: 100%;
}
thead {
background-color: lightgrey;
text-align: left;
}
.notes {
text-align: right;
}
<button class="dmgSort">Sort By DMG Ascending</button>
<table>
<thead>
<tr>
<th>Command</th>
<th>DMG</th>
<th>EXE</th>
<th>TOT</th>
</tr>
</thead>
<tbody>
<tr>
<td>Jouho Touken</td>
<td>19</td>
<td>17</td>
<td>42</td>
</tr>
<tr>
<td colspan="4" class="notes">Opponent crouching (H: Stagger)</td>
</tr>
<tr>
<td>Chouyoushu</td>
<td>25</td>
<td>18</td>
<td>46</td>
</tr>
<tr>
<td colspan="4" class="notes">Damage varies due to distance (25-40)</td>
</tr>
<tr>
<td>Tetsuzankou</td>
<td>40</td>
<td>19</td>
<td>75</td>
</tr>
<tr>
<td colspan="4" class="notes">Super Replay; Damage varies due to distance: 40-80</td>
</tr>
</tbody>
</table>

Categories