Table Search only first TD - javascript

I have a javascript search function that works very well. However, it only searches the first td in the table and no others.
It appears to be working only for the tr
Full Code:
PHP:
Create a table to display the output
echo '<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Search for names..">';
echo '<div class="table-responsive">';
echo '<table id="myTable"><tr bgcolor="#cccccc"><td>Name</td><td>Department</td><td>E-Mail Address</td><td>Office Phone</td><td>Mobile</td></tr>';
For each account returned by the search
for ($x=0; $x<$entries['count']; $x++){
Retrieve values from Active Directory
First Name
$LDAP_FirstName = "";
if (!empty($entries[$x]['givenname'][0])) {
$LDAP_FirstName = $entries[$x]['givenname'][0];
if ($LDAP_FirstName == "NULL"){
$LDAP_FirstName = "";
}
}
Last Name
$LDAP_LastName = "";
if (!empty($entries[$x]['sn'][0])) {
$LDAP_LastName = $entries[$x]['sn'][0];
if ($LDAP_LastName == "NULL"){
$LDAP_LastName = "";
}
}
Department
$LDAP_Department = "";
if (!empty($entries[$x]['department'][0])) {
$LDAP_Department = $entries[$x]['department'][0];
if ($LDAP_Department == "NULL"){
$LDAP_Department = "";
}
}
Email address
$LDAP_InternetAddress = "";
if (!empty($entries[$x]['mail'][0])) {
$LDAP_InternetAddress = $entries[$x]['mail'][0];
if ($LDAP_InternetAddress == "NULL"){
$LDAP_InternetAddress = "";
}
}
IPPhone
$LDAP_OfficePhone = "";
if (!empty($entries[$x]['ipphone'][0])) {
$LDAP_OfficePhone = $entries[$x]['ipphone'][0];
if ($LDAP_OfficePhone == "NULL"){
$LDAP_OfficePhone = "";
}
}
Mobile Number
$LDAP_CellPhone = "";
if (!empty($entries[$x]['mobile'][0])) {
$LDAP_CellPhone = $entries[$x]['mobile'][0];
if ($LDAP_CellPhone == "NULL"){
$LDAP_CellPhone = "";
}
}
Fill the table
echo "<tr><td>".$LDAP_FirstName." " .$LDAP_LastName."</td><td>".$LDAP_Department."</td><td><a class='one' href='mailto:" .$LDAP_InternetAddress. "'>" .$LDAP_InternetAddress."</td><td>".$LDAP_OfficePhone."</td><td>".$LDAP_CellPhone."</td><tr>";
} //END for loop
} //END FALSE !== $result
ldap_unbind($ldap_connection); // Clean up after ourselves.
echo("</table>");
echo("</div>");
} //END ldap_bind
Javascript:
function myFunction() {
// 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 = 1; 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";
}
}
}
}
Updated with full code. Thanks

I would probably do it like this, I made a few small updates to the table structure (separating head from body) and used a class instead of an inline style for visibility changes.
HTMLTableElement has a few useful timesavers for getting into the dom object (tBodies, rows). Using that method to access the table you can then either use Object.keys() like I have here or a standard for ...in loop to iterate through and check your conditions.
I usually consider re-searching to be a reset so will make everything invisible by default and then only show matches, this also cleans up the code by removing the need for an else.
I appended numbers to the first td in the table to make demonstrating search easy, just pick a number.
function myFunction() {
let rows = document.getElementById('myTable').tBodies[0].rows;
Object.keys(rows).forEach(key => {
rows[key].classList.add('filter');
const input = document.getElementById('myInput').value.toUpperCase();
const current = rows[key].cells[0].innerText.toUpperCase()
if (current.indexOf(input) > -1) {
rows[key].classList.remove('filter');
}
});
}
.filter { display: none; }
<input type="text" id="myInput" onkeyup="myFunction()" placeholder="Search for names..">
<div class="table-responsive">
<table id="myTable">
<thead>
<tr>
<th>Name</th>
<th>Department</th>
<th>E-Mail Address</th>
<th>Office Phone</th>
<th>Mobile</th>
</tr>
</thead>
<tbody>
<tr>
<td>search1</td></td><td>Department</td><td>E-Mail Address</td><td>Office Phone</td><td>Mobile</td>
</tr>
<tr>
<td>search2</td></td><td>Department</td><td>E-Mail Address</td><td>Office Phone</td><td>Mobile</td>
</tr>
<tr>
<td>search3</td></td><td>Department</td><td>E-Mail Address</td><td>Office Phone</td><td>Mobile</td>
</tr>
<tr>
<td>search4</td></td><td>Department</td><td>E-Mail Address</td><td>Office Phone</td><td>Mobile</td>
</tr>
<tr>
<td>search5</td></td><td>Department</td><td>E-Mail Address</td><td>Office Phone</td><td>Mobile</td>
</tr>
</tbody>
</table>

You have to add for inner for. First 'for' for the next td and other 'for' for the next tr.

Related

How to include a clickable link or button for each record? HTML + Array + Tables

I have learnt a sample code from youtube on putting an array in HTML table dynamically that is sortable. Below is the code.
How do I made each record in display HTML table clickable and call a myFunction()? The myFunction() will then get the value of the Name in the respective row and execute another query.
HTML Part ->
<table class="table table-striped">
<tr class="bg-info">
<th data-column="name" data-order="desc">Name &#9650</th>
<th data-column="age" data-order="desc">Age &#9650</th>
<th data-column="birthdate" data-order="desc">Birthday &#9650</th>
</tr>
<tbody id="myTable">
</tbody>
the javascript part
var myArray = [
{'name':'Michael', 'age':'30', 'birthdate':'11/10/1989'},
{'name':'Mila', 'age':'32', 'birthdate':'10/1/1989'},
{'name':'Paul', 'age':'29', 'birthdate':'10/14/1990'},
{'name':'Dennis', 'age':'25', 'birthdate':'11/29/1993'},
{'name':'Tim', 'age':'27', 'birthdate':'3/12/1991'},
{'name':'Erik', 'age':'24', 'birthdate':'10/31/1995'},
]
$('th').on('click', function(){
var column = $(this).data('column')
var order = $(this).data('order')
var text = $(this).html()
text = text.substring(0, text.length - 1)
if(order == 'desc'){
$(this).data('order', "asc")
myArray = myArray.sort((a,b) => a[column] > b[column] ? 1 : -1)
text += '&#9660'
}else{
$(this).data('order', "desc")
myArray = myArray.sort((a,b) => a[column] < b[column] ? 1 : -1)
text += '&#9650'
}
$(this).html(text)
buildTable(myArray)
})
buildTable(myArray)
function buildTable(data){
var table = document.getElementById('myTable')
table.innerHTML = ''
for (var i = 0; i < data.length; i++){
var row = `<tr>
<td>${data[i].name}</td>
<td>${data[i].age}</td>
<td>${data[i].birthdate}</td>
</tr>`
table.innerHTML += row
}
}
My Function Call Js part
function myFunction() { " wanna get the value of the row if link is click" }
You need to add the following after you call the buildTable(myArray) so the <tr> tags can render before you assign them a click event.
$('tr').click(function(){
var name = $(this).children('td').first().html();
yourFunction(name);
});
function yourFunction(name){
//do things with name here
}
Also, this assumes that the first td will always contain the name. A better implementation would be to refactor the buildTable function and give classes to your td
$(document).on("click", "tbody tr", function(){
//if you want name field
$(this).find("td:nth-child(1)").text();
//if you want age field
$(this).find("td:nth-child(2)").text();
});
i done the myFunction in Jquery, use this code inside your script tag

Search Bar in HTML and JS

I created an HTML table with a lot of information about a country. Now I want the user to be able to search in this table for a piece of information like the Area.
function selectRow() {
var input, filter, table, trs, td;
input = document.getElementById("search");
filter = input.value.toUpperCase();
table = document.getElementById("dataRows");
trs = table.getElementsByTagName("tr");
for (let index = 0; index < trs.length; index++) {
td = trs[index].getElementsByTagName("td")[0];
if (td.innerHTML.toUpperCase().indexOf(filter) > -1) {
trs[index].display = "";
} else {
trs[index].display = "none";
}
}
}
<input type="text" id="search" onkeyup="selectRow()" placeholder="Search.." />
<table id="dataRows">
<tr>
<th>Attributes</th>
<th>Value</th>
</tr>
<tr>
<td>Name</td>
<td>Australia</td>
</tr>
<tr>
<td>Area</td>
<td>7,741,220.00</td>
</tr>
<tr>
<td>Population</td>
<td>25,466,459</td>
</tr>
</table>
But when I try to use it I get the error: "Uncaught TypeError: Cannot read property 'innerHTML' of undefined"
I can't figure out why the td is undefined.
The most helpful thing to demonstrate first, I think, is a method that will let you diagnose this yourself in future. This sort of difficulty will occur all the time, so here is one method to help you generally problem solve these types of issues.
You know that <td> is not the value you expect, so check your expectation by outputting the values that you use to acquire <td>. You can do that by adding these console.log lines at the top of your loop:
for (let index = 0; index < trs.length; index++) {
console.log("trs[index]",trs[index]);
console.log("trs[index].getElementsByTagName(td)", trs[index].getElementsByTagName("td"));
With that, you should see that the first <tr> has <th> elements, not <td>! These surprises happen all the time, it's great to learn tricks to check your assumptions the quickest way you can.
Here's a very simple solution, the first and last line of this block are the same in your code:
for (let index = 0; index < trs.length; index++) {
var tds = trs[index].getElementsByTagName("td");
if(tds.length == 0) {
continue;
}
td = tds[0];
if (td.innerHTML.toUpperCase().indexOf(filter) > -1) {
Looks like you've just started working through building this, I hope this helps!
<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('li');
// 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("a")[0];
txtValue = a.textContent || a.innerText;
if (txtValue.toUpperCase().indexOf(filter) > -1) {
li[i].style.display = "";
} else {
li[i].style.display = "none";
}
}
}
</script>
use ur code like this to get best result and without any error
edit
I think the tricky part of this is actually the accepting of user input intelligently. Therefore, I'd say the best thing to do is to pass off your searching to an autocomplete-type plugin. Once the page is ready, you pass the focus to an input text box, and then let the plugin do its magic as you search...
For example, you could use the quicksearch plugin.
Then given a table of data and an input like this:
<input id="searcher" type="text" name="searcher">
You could have a ready function that looks like this:
$('#searcher').quicksearch('table tbody tr', {
'delay': 100,
'bind': 'keyup keydown',
'show': function() {
if ($('#searcher').val() === '') {
return;
}
$(this).addClass('show');
},
'onAfter': function() {
if ($('#searcher').val() === '') {
return;
}
if ($('.show:first').length > 0){
$('html,body').scrollTop($('.show:first').offset().top);
}
},
'hide': function() {
$(this).removeClass('show');
},
'prepareQuery': function(val) {
return new RegExp(val, "i");
},
'testQuery': function(query, txt, _row) {
return query.test(txt);
}
});
$('#searcher').focus();
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Try it out here: http://jsfiddle.net/ZLhAd/369/

How can I add <td> tags to my html table with JavaScript?

I'm trying to use the insertcell method to add a column to my table but either I'm getting the syntax wrong or it isn't working. I wondered if anyone could explain where I am going wrong?
The table body in the html is populated dynamically with some other JavaScript but I don't think this is the problem as I've tested grabbing some content from that table with an alert box and it works (commented out below):
<!DOCTYPE html>
<script type="text/javascript" src="fullstationxyparser.js">
</script>
<html>
<body>
<table border=1>
<thead>
<tr>
<td>Element Name</td>
<td>x</td>
<td>y</td>
<td>testCol</td>
</tr>
</thead>
<tbody id="stationlist">
</tbody>
</table>
</body>
</html>
function addStationNames() {
var myTable = document.getElementById("stationlist");
var stationListRows = myTable.getElementsByTagName('tr');
for (var i = 1; i < stationListRows.length; i++) {
var cell = stationListRows[i].getElementsByTagName('td');
var stationName = cell[0].innerHTML; //get station id from element Name column
var currentRow = stationListRows[i];
var newCol = currentRow.insertcell(-1);
newCol.innerHTML = stationName;
//alert(stationName);
}
}
In Firefox developer tools, I get TypeError: "currentRow.insertcell is not a function". Perhaps I can't use the insertcell method on a row collection?
In general you can call the insertRow() method on a Table DOM element, followed by calls to the insertCell() method as shown below to dynamically add <td> tags to your table with JavaScript.
Be careful to call insertCell() (with capital C) rather than insertcell() as you are currently doing:
const table = document.querySelector('table');
/* Insert new row */
const row = table.insertRow();
/* Insert cells (td) for row */
const td0 = row.insertCell(0);
const td1 = row.insertCell(1);
const td2 = row.insertCell(2);
const td3 = row.insertCell(3);
/* Populate cells with data */
td0.innerText = 'Foo';
td1.innerText = '3';
td2.innerText = '6';
td3.innerText = 'success';
<table border="1">
<thead>
<tr>
<td>Element Name</td>
<td>x</td>
<td>y</td>
<td>testCol</td>
</tr>
</thead>
<tbody>
</tbody>
</table>
Specific to your code, some other changes to consider might be as listed in this code snippet:
function addStationNames() {
/* Condense table row access into single query */
const stationRows = document.querySelectorAll("#stationlist tr");
stationRows.forEach((stationRow, i) => {
/* Skip first row */
if(i === 0) { return; }
/* Get station name from text of first cell */
const stationName = stationRow.querySelector('td:first-child').innerText;
/* Insert last cell on row and assign station name */
stationRow.insertCell(-1).innerText = stationName;
});
/*
Old code:
for (let i = 1; i < stationListRows.length; i++) {
var cell = stationListRows[i].getElementsByTagName('td');
var stationName = cell[0].innerHTML;
var currentRow = stationListRows[i];
var newCol = currentRow.insertcell(-1);
newCol.innerHTML = stationName;
}
*/
}
addStationNames();
<!-- set table id to stationlist -->
<table border="1" id="stationlist">
<thead>
<tr>
<td>Element Name</td>
<td>x</td>
<td>y</td>
<td>testCol</td>
</tr>
<tr>
<td>90's pop</td>
<td>232</td>
<td>543</td>
</tr>
</thead>
<tbody>
<!-- Remove id from tbody -->
</tbody>
</table>
An alternative to the answer above (which is totally fine) is this method, which is also a more general method of creating any html element:
const table = document.getElementById('one');
const newRow = document.createElement("tr");
let newCell = document.createElement("td");
newCell.textContent = "first cell";
let newCell2 = document.createElement("td");
newCell2.textContent = "second cell";
newRow.appendChild(newCell);
newRow.appendChild(newCell2);
table.appendChild(newRow);
https://jsfiddle.net/zgaosdbv/

Multiple filters for html table

I have an html table in my view that I want to filter with multiple filters. In this case, I have 3 filters, but I can have much more.
Here is a little part of the code, to show the problem
$(document).ready(function () {
$('#datefilterfrom').on("change", filterRows);
$('#datefilterto').on("change", filterRows);
$('#projectfilter').on("change", filterProject);
$('#servicefilter').on("change", filterService);
});
function filterRows() {
var from = $('#datefilterfrom').val();
var to = $('#datefilterto').val();
if (!from && !to) { // no value for from and to
return;
}
from = from || '1970-01-01'; // default from to a old date if it is not set
to = to || '2999-12-31';
var dateFrom = moment(from);
var dateTo = moment(to);
$('#testTable tr').each(function (i, tr) {
var val = $(tr).find("td:nth-child(2)").text();
var dateVal = moment(val, "DD/MM/YYYY");
var visible = (dateVal.isBetween(dateFrom, dateTo, null, [])) ? "" : "none"; // [] for inclusive
$(tr).css('display', visible);
});
}
function filterProject() {
let dumb = this.options.selectedIndex;
dumb = this.options[dumb].innerHTML;
var filter, table, tr, td, i;
filter = dumb.toUpperCase();
table = document.getElementById("testTable");
tr = table.getElementsByTagName("tr");
for (i = 0; i < tr.length; i++) {
td = tr[i].getElementsByTagName("td")[2];
if (td) {
if (td.innerHTML.toUpperCase().indexOf(filter) > -1) {
tr[i].style.display = "table-row";
} else {
tr[i].style.display = "none";
}
}
}
}
function filterService() {
let dumb = this.options.selectedIndex;
dumb = this.options[dumb].innerHTML;
var filter, table, tr, td, i;
filter = dumb.toUpperCase();
table = document.getElementById("testTable");
tr = table.getElementsByTagName("tr");
for (i = 0; i < tr.length; i++) {
td = tr[i].getElementsByTagName("td")[3];
if (td) {
if (td.innerHTML.toUpperCase().indexOf(filter) > -1) {
tr[i].style.display = "table-row";
} else {
tr[i].style.display = "none";
}
}
}
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://rawgit.com/moment/moment/2.2.1/min/moment.min.js"></script>
<div class="row">
<div class="col-md-3">
<h4>Date from</h4>
<input type="date" class="form-control" id="datefilterfrom" data-date-split-input="true">
</div>
<div class="col-md-3">
<h4>Date to</h4>
<input type="date" class="form-control" id="datefilterto" data-date-split-input="true">
</div>
<div class="col-md-2">
<h4>Project</h4>
<select id="projectfilter" name="projectfilter" class="form-control"><option value="1">Test project</option><option value="2">Test2</option></select>
</div>
<div class="col-md-2">
<h4>Service</h4>
<select id="servicefilter" name="servicefilter" class="form-control"><option value="1">Test service</option><option value="2">Test2 service</option></select>
</div>
</div>
<table id="testTable" class="table">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">Date</th>
<th scope="col">Project</th>
<th scope="col">Service</th>
</tr>
</thead>
<tbody id="report">
<tr>
<td class="proposalId">9</td><td> 17/07/2018</td> <td> Test project</td><td> Test service</td>
</tr>
<tr><td class="proposalId">8</td><td> 18/07/2018</td><td> Test project</td><td> Test2 service</td></tr>
<tr><td class="proposalId">7</td><td> 17/07/2018</td><td> Test2</td><td> Test2 service</td></tr>
<tr style=""><td class="proposalId">3</td><td> 19/07/2018</td><td> Test2</td><td> Test service</td></tr>
</tbody>
</table>
If you set filters like this
You will have this
This is not right. Because I need to have only test 2 project, so one row.
Where is my problem and How I can solve it?
Here is codepen for code
https://codepen.io/suhomlineugene/pen/pZqyEN
Right now you have a separate function for each of your filters, each of which ignores the settings from the other filters and overwrites their results.
Instead you'll need to combine those into a single function which takes all the filters into account.
Rather than literally combining all the code into one complex function, which would be difficult to maintain, one approach would be to have a single master function that makes all the rows visible, then calls each of the other filter functions in turn; those functions would only hide the rows they're filtering out. What's left visible at the end would be the rows that match all the filter selections.
$(document).ready(function () {
$('#datefilterfrom, #datefilterto, #projectfilter, #servicefilter').on("change", filterAll);
});
function filterAll() {
$('#testTable tr').show();
filterRows();
filterProject();
filterService();
// ...etc
}
function filterRows() { // repeat for filterProject(), filterService(), etc
// same as your original code, except only hide non-matching rows, do not
// show matching rows (because filterAll() already took care of that, and
// you don't want to undo what other filters may have hidden.)
}
(Alternatively, instead of showing everything and then having each individual filter hide rows incrementally, you could have filterAll() build an array of all the rows, pass it to the individual filter functions which will remove items from it, then use the end result to show/hide the appropriate rows in one go.)
Not going to rewrite this all for you but will give you a basic outline for the text only searches:
Create array of the filter data from the top inputs. By adding a data-col to each of those filter controls you can easily determine which column in table to match to
So the filters array would look something like:
[
{col:3, value:'test project'}
]
Then use jQuery filter() on the rows and use Array#every() on the filterValues array and look for the matching cell text using the column index from each filter object
var $rows = $('tbody#report tr')
// add a class `table-filter` to all the top filtering elements
var $filters = $('.table-filter').change(function() {
// create array of filter objects
var filterArr = $filters.filter(function() {
return this.value
}).map(function() {
var $el = $(this);
var value = $el.is('select') ? $el.find(':selected').text() : $el.val()
return {
col: $el.data('col'),
value: value.toLowerCase()
}
}).get();
if (!filterArr.length) {
// no filters show all rows
$rows.show()
} else {
// hide all then filter out the matching rows
$rows.hide().filter(function() {
var $row = $(this);
// match every filter to whole row
return filterArr.every(function(filterObj, i) {
var cellText = $row.find('td').eq(filterObj.col).text().trim().toLowerCase();
return cellText.includes(filterObj.value);
})
})
// show the matches
.show()
}
});
Working demo for the two text search fields

Filtering table rows upon Search

I am trying to filter the rows of a table to display the results of entered text in the search bar. The code below does the job but for some reason filters the column headings as well.
$('#search').keyup(function () {
var data = this.value.split(" ");
var rows = $(".Info").find("tr").hide();
if(this.value ==""){
rows.show();
return;
}
rows.hide();
rows.filter(function(i,v){
var t = $(this);
for (var d = 0; d < data.length; d++) {
if (t.is(":Contains('" + data[d] + "')")) {
return true;
}
}
return false;
}).show();
});
HTML
<input type = "search" name = "search" id = "search">
<table style ="width:95%" class = "Info">
<tr>
<th>Select </th>
<th>Name</th>
<th>Number</th>
<th>Date</th>
</tr>
</table>
The user adds rows which is why i haven't written any HTML for it.
Any help would be appreciated. Thanks in advance
http://jsfiddle.net/szjhngwm/
It looks like you need to filter using tbody
<table style ="width:95%" class = "Info">
<thead>
<tr>
<th>Select </th>
<th>Name</th>
<th>Number</th>
<th>Date</th>
</tr>
<thead>
<tbody>
</tbody>
</table>
var rows = $(".Info tbody tr").hide();
Another way to do this would be to use jQuery's :gt() selector.
The only thing that would change is this line:
var rows = $(".Info").find("tr:gt(0)").hide();
Notice the addition of :gt(0) to your tr.

Categories

Resources