Javascript-Search function interesting behavior in IE - javascript

Im using a search function to search inside a table, and hide collumns which not contain the searchterm.
This works perfect in my project on Firefox,Opera, and Safari. But not in IE, the Search function is not working.
JS:
function doSearch() {
var searchText = document.getElementById('searchTerm').value.toLowerCase(),
table = document.getElementById('dataTable'),
text = (document.body.textContent) ? 'textContent' : 'innerText', // Feature detection
rows = table.rows, // Caching rows
rLen = rows.length,
r, rowText, cells, cols, c;
for (r = 1; r < rLen; r++) { // Ignoring the first row
if (rows[r].className.indexOf('search_for') < 0) {continue;} // className check
rowText = '';
cells = rows[r].cells; // Caching the cells
cols = cells.length;
for (c = 0; c < cols; c++) {
rowText += cells[c][text];
}
rowText = rowText.toLowerCase();
if (rowText.indexOf(searchText) < 0) {
table.rows[r].style.display = 'none';
} else {
table.rows[r].style.display = 'table-row';
}
}
}
HTML:
<table id="searchTerm">
<?php while($info = mysqli_fetch_array($data )): ?>
<tr id="tr_<?php echo $info['ID'];?>" class="search_for">
<td><?php echo $info['text'];?></td>
</tr>
<tr id="detail_tr_<?php echo $info['ID'];?>" >
<td>detail text....</td>
</tr>
<?php endwhile; ?>
<tr id="test"><td>X</td></tr>
</table>
The php while will output a few rows.
So, what i found out.
the rows = table.rows, in the Javascript only notcices the <tr>'s which have an "detail_tr" as id, the normal ones "tr_" dont get noticed.
another very strange thing is, in Debbuger from IE, i can see what "rows" contains.
<tr> with an "detail_tr" get detected as [objectHTMLTableRowElement]
<tr> with the "test" as id, gets detected as [objectHTMLCollection]
I added an image, in the upper part you can see the debugger, and in the lower part you see html explorer : http://postimg.org/image/94leleccj/
What could be the Problem here?!

I created a jsfiddle.net of your code and it's working quite fine in IE9+
JavaScript:
function doSearch() {
var searchText = document.getElementById('searchTerm').value.toLowerCase(),
table = document.getElementById('dataTable'),
text = (document.body.textContent) ? 'textContent' : 'innerText', // Feature detection
rows = table.rows, // Caching rows
rLen = rows.length,
r, rowText, cells, cols, c;
for (r = 1; r < rLen; r++) { // Ignoring the first row
if (rows[r].className.indexOf('search_for') < 0) {continue;} // className check
rowText = '';
cells = rows[r].cells; // Caching the cells
cols = cells.length;
for (c = 0; c < cols; c++) {
rowText += cells[c][text];
}
rowText = rowText.toLowerCase();
if (rowText.indexOf(searchText) < 0) {
table.rows[r].style.display = 'none';
document.getElementById('detail_' + table.rows[r].id).style.display = 'none';
} else {
table.rows[r].style.display = 'table-row';
document.getElementById('detail_' + table.rows[r].id).style.display = 'table-row';
}
}
}
HTML:
<input type="text" id="searchTerm" /> <button onclick="doSearch()">doSearch()</button>
<table id="dataTable">
<tr><th>table</th></tr>
<tr id="tr_1" class="search_for">
<td>bar</td>
</tr>
<tr id="detail_tr_1" >
<td>foo bar</td>
</tr>
<tr id="tr_2" class="search_for">
<td>baz</td>
</tr>
<tr id="detail_tr_2" >
<td>foo baz</td>
</tr>
<tr id="test"><td>X</td></tr>
</table>

Related

How to highlight a table row with the smallest value in a certain column using javascript

Supposed that I have a table like this on a webpage with the id ='table':
Name Age Money(USD) DATE
A 19 4 2019-03-11 16:15:35
B 20 0 2019-03-11 16:16:37
C 27 3 2019-03-13 04:15:43
D 34 0 2019-03-13 04:16:57
Could you help me find the FIRST SMALLEST VALUE IN THE MONEY COLUMN, which is 0 for B in the Column1 and HIGHLIGHT the whole table row for B, using javascript without using any library and any button onClicking?
Note: I have searched around and just been unlucky enough to find the correct answer to my problem.
Thanks.
UPDATE:I just got a piece of javacript like this to get the first smallest value and print it out, but not be able to highlight the whole row with it
var table = document.getElementById("table"), minVal;
for(var i = 1; i < table.rows.length; i++)
{
// if its the first row get the value
if(i === 1){minVal = table.rows[i].cells[2].innerHTML; }
// test with the other values
else if(minVal > table.rows[i].cells[2].innerHTML){
minVal = table.rows[i].cells[2].innerHTML;
}
}
document.getElementById("val").innerHTML = " Minimum Value = "+minVal;
console.log(maxVal);
var table = document.getElementById("table"), minVal, minI;
for(var i = 1; i < table.rows.length; i++){
if(i === 1){
minVal = table.rows[i].cells[2].innerHTML;
}
else if(minVal > table.rows[i].cells[2].innerHTML){
minVal = table.rows[i].cells[2].innerHTML;
minI = i;
}
}
table.rows[i].cells[2].innerHTML = '<span style="background:red">' + table.rows[minI].cells[2].innerHTML + '</span>';
Something like that.
var table = document.getElementById("table");
var minVal = undefined;
for(var i = 1; i < table.rows.length; i++)
{
if(i === 1){
minVal = table.rows[i].cells[2];
}
else if(minVal.innerHTML > table.rows[i].cells[2].innerHTML){
minVal = table.rows[i].cells[2];
}
}
minVal.parentElement.style.background="yellow";
There are two things you need to do:
Convert innerHTML to a number using +
Keep track of the row number while looping.
This is the code
var table = document.getElementById("table"), minVal;
let minRow = 1;
for(var i = 1; i < table.rows.length; i++)
{
// if its the first row get the value
if(i === 1){
minVal = +table.rows[i].cells[2].innerHTML;
}
// test with the other values
else if(minVal > table.rows[i].cells[2].innerHTML){
minVal = table.rows[i].cells[2].innerHTML;
minRow = i;
}
}
let row = table.rows[minRow];
row.style.backgroundColor = 'red';
This simply keeps track of the minimum row, and lets you hang your formatting off of that:
const highlightLowest = () => {
var rows = table.rows;
var minRow = rows[0]
for (var i = 1; i < rows.length; i++){
rows[i].classList.remove('highlight')
if (Number(rows[i].cells[2].innerHTML) < Number(minRow.cells[2].innerHTML)) {
minRow = rows[i]
}
}
minRow.classList.add('highlight')
}
tr.highlight td {background-color: yellow}
<table id="table">
<tr><td>A</td><td>19</td><td>4</td><td>2019-03-11 16:15:35</td></tr>
<tr><td>B</td><td>20</td><td>0</td><td>2019-03-11 16:16:37</td></tr>
<tr><td>C</td><td>27</td><td>3</td><td>2019-03-13 04:15:43</td></tr>
<tr><td>D</td><td>34</td><td>0</td><td>2019-03-13 04:16:57</td></tr>
</table>
<hr />
<button onClick="highlightLowest()">Highlight</button>
Here you go. The function 'highlight' takes the column that you want to base your highlighting upon as an argument.
// Get your table's headers
headers = document.querySelectorAll('#table tbody tr th')
// Get your table's headers
rows = document.querySelectorAll('#table tbody tr')
// Declaring function that takes wanted column as argument
highlight = (colName) =>{
let min = 0;
for(i=0;i<headers.length;i++){
if(headers[i].innerText == colName){
for(j=1;j<rows.length;j++){
value = parseInt(rows[j].children[i].innerHTML);
if(j == 1){
min = value;
}
if(value < min){
rows[j].style.backgroundColor = "yellow"
break;
}
}
}
}
}
<table id="table">
<tbody><tr>
<th>Test 1</th>
<th>Test 2</th>
<th>Test 3</th>
</tr>
<tr>
<td>7</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>3</td>
<td>5</td>
<td>5</td>
</tr>
<tr>
<td>12</td>
<td>1</td>
<td>5</td>
</tr>
<tr>
<td>15</td>
<td>89</td>
<td>4</td>
</tr>
<tr>
<td>3</td>
<td>6</td>
<td>6</td>
</tr>
<tr>
<td>2</td>
<td>4</td>
<td>8</td>
</tr>
</tbody></table>
<input type='text' id='col'>
<button onclick=highlight(document.getElementById('col').value)>Highlight based on input column</button>

Search for a tag's name inside of a cell inside of each row

So pretty much I have it to were it's searching for the innerHTML of the td in question in each row....however I'm trying to grab the input name attribute from below
<table>
<tbody>
<tr>
<td><input name="Client"></td>
</tr>
</tbody>
</table>
Here's what i have so far
var q = document.getElementById("q");
var v = q.value.toLowerCase();
var rows = document.getElementsByTagName("tr");
var on = 0;
for (var i = 0; i < rows.length; i++) {
var fullname = rows[i].getElementsByTagName("td");
fullname = fullname[0].innerHTML.toLowerCase();
if (fullname) {
if (v.length == 0 ||
(v.length < 3 && fullname.indexOf(v) == 0) ||
(v.length >= 3 && fullname.indexOf(v) > -1)) {
rows[i].style.display = "";
on++;
} else {
rows[i].style.display = "none";
}
}
}
var n = document.getElementById("noresults");
if (on == 0 && n) {
n.style.display = "";
document.getElementById("qt").innerHTML = q.value;
} else {
n.style.display = "none";
}
However right now it's only indicating within the td.... How do I get the above to look for the name of the input inside of the td?
Much appreciated.
You don't need a lot of code for that. On most modern browser this works.
//For 1 value
myInput = document.querySelector('#tablename td [name="Client"]');
console.log(myInput);
//For more values
myInput2 = document.querySelectorAll('#tablename td [name="Client"]');
console.log(myInput2); //it's an array now
//Like this?
myInput3 = document.querySelector('#tablename td [name]');
if(myInput3.getAttribute('name') == 'Client'){
myInput3.setAttribute('name', 'something');
}
console.log(myInput3.parentElement);
<table id="tablename">
<tr>
<td><input name="Client"></td>
</tr>
</table>
If you have a reference to the <td> element, you can use querySelector to get a reference to the <input> (assuming it's the only or first <input> descendant) and then getAttribute to get the value of the name attribute:
// You already have a reference to the <td>
const td = document.querySelector('td');
// Get the <input>
const input = td.querySelector('input');
// Get its `name` attribute
const name = input.getAttribute('name');
console.log('name is "%s"', name);
<table>
<tbody>
<tr>
<td><input name="Client"></td>
</tr>
</tbody>
</table>

How to better formatting my HTML Table with titles and labels

How would I modify my code (below) to turn the table element (circled in red), into a table with a Title, and then headers above each column ("Load" and "kWh") for the left and right columns, respectively?
The elements, "name" and "watts" are what I want to create a label for ("Load" and "kWh"), in addition to a title above the table which says "Power Usage". Right now, there is no formatting, and I am having trouble going from the tutorials at W3 schools, into my code.
function(){
var wrapper = document.createElement("div");
if(!this.loaded) {
wrapper.innerHTML = "Loading...";
return wrapper;
}
if(this.xml !== null){
var table = document.createElement("table");
table.classList.add("xsmall", "table");
var channels = this.xml.getElementsByTagName("channel");
for(var i = 0; i < channels.length; i++){
var row = document.createElement("tr");
for(var n = 0; n < channels[i].children.length; n++){
if(channels[i].children[n].tagName === "name" || channels[i].children[n].tagName === "watts"){
var element = document.createElement("td");
element.classList.add(channels[i].children[n].tagName);
if (channels[i].children[n].textContent != 0){
element.innerHTML = channels[i].children[n].textContent;
row.appendChild(element);
table.appendChild(row);
}
else {
table.removeChild(row); }
}
}
}
wrapper.appendChild(table);
} else {
console.log("Returned no Data");
wrapper.innerHTML = "NO DATA";
}
return wrapper;
},
First Try:
You just want to build out a table similar to the following using the JS you've already written:
<table>
<caption>Put title here</caption>
<thead>
<tr>
<th>Load</th>
<th>kWh</th>
</tr>
</thead>
<tbody>
<tr>
<td>Kitchen Lights</td>
<td>2.799</td>
</tr>
</tbody>
</table>

How can jQuery select Table Row group by Colum's value?

I have a problem regarding jQuery selector, where I have a Table structure as below (HTML Portion), and there is a link in table column for click and move the Table Row "UP" and "Down" by using jQuery (jQuery Portion, reference from this post).
jQuery Portion :
$(".up,.down").click(function() {
var row = $(this).parents("tr:first");
if ($(this).is(".up")) {
row.insertBefore(row.prev("tr:has(td)"));
} else {
row.insertAfter(row.next());
}
});
HTML Portion :
<table cellspacing="0" border="0" id="Table1" style="text-align:center" >
<tr>
<th scope="col" width="80px">Column A</th><th scope="col" width="80px">Column B</th><th scope="col"> </th>
</tr>
<tr>
<td>
<span id="GridView1_ctl02_lbl1">A</span>
</td><td>
<span id="GridView1_ctl02_lbl2">0</span>
</td><td>
Up Down
</td>
</tr><tr>
<td>
<span id="GridView1_ctl03_lbl1">B</span>
</td><td>
<span id="GridView1_ctl03_lbl2">2</span>
</td><td>
Up Down
</td>
</tr><tr>
<td>
<span id="GridView1_ctl04_lbl1">C</span>
</td><td>
<span id="GridView1_ctl04_lbl2">2</span>
</td><td>
</td>
</tr><tr>
<td>
<span id="GridView1_ctl05_lbl1">D</span>
</td><td>
<span id="GridView1_ctl05_lbl2">2</span>
</td><td>
</td>
</tr><tr>
<td>
<span id="GridView1_ctl06_lbl1">E</span>
</td><td>
<span id="GridView1_ctl06_lbl2">3</span>
</td><td>
Up Down
</td>
</tr>
</table>
I wanted the Row to be move "UP" and "Down" group by values in "Column B" (as per highlighted with red box") instead of ordinary row by row. Based on example of the diagram, the moving of rows should be move by the red boxes.
So my question is, how can I using jQuery selector to select rows group by value in "Column B"? which the onclick event was trigger on links ("Up" & "Down") click.
Thank you in advanced :)
I don't think you can do this with Just selectors and a single command! but you can use some loops :
$(".up,.down").click(function () {
var row = $(this).parents("tr:first");
if ($(this).is(".up")) {
myRow = row;
prevRow = row.prev("tr");
currentValue = myRow.children("td").eq(1).text();
prevValue = prevRow.children("td").eq(1).text();
parNode = myRow.parent();
i = 0;
family = [];
parNode.children("tr").each(function(){
if($(this).children("td").eq(1).text() == currentValue){
family[i] = $(this);
i++;
}
});
for(var j = 0; j <= i; j++ ){
while(prevRow.children("td").eq(1).text() == prevValue){
prevRow = prevRow.prev("tr");
}
family[j].insertAfter(prevRow);
}
} else {
row.insertAfter(row.next());
}
});
Demo here: http://jsfiddle.net/shahverdy/PSDEs/2/
In this demo I implemented only Up. Click Up for values 2 and 3 to see how it works.
Given the table structure above, you can make a map storing (value in column b, corresponding tr array) pairs, if all the rows that have the same value in column B are adjacent. And when you click the Up/Down link, detach all the rows with the same value and get the rows above (for Up) or bellow (for Down). Then you know where to attach those detached rows.
$(function() {
var column_index = 1;
function get_value(tr) {
return $('td', tr).eq(column_index).text().trim();
}
function group_by(trs, column_index) {
var map = {};
trs.each(function (idx) {
var value = get_value($(this));
if (map[value])
map[value].push($(this));
else
map[value] = [$(this)];
});
return map;
}
var map = group_by($('#Table1 tr:gt(0)'), column_index);
$('a.up').click(function () {
var tr = $(this).closest('tr');
var value = get_value(tr);
var group = map[value];
var prev = group[0].prev('tr');
if (prev.length == 0 || $('th', prev).length != 0)
return;
var prev_value = get_value(prev);
var prev_group = map[prev_value];
for (var i = 0; i < group.length; i++) {
group[i].detach();
prev_group[0].before(group[i]);
}
});
$('a.down').click(function () {
var tr = $(this).closest('tr');
var value = get_value(tr);
var group = map[value];
var next = group[group.length - 1].next('tr');
if (next.length == 0)
return;
var next_value = get_value(next);
var next_group = map[next_value];
for (var i = group.length - 1; i >= 0; i--) {
group[i].detach();
next_group[next_group.length - 1].after(group[i]);
}
});
});
Refer to the code example at jsFiddle.
If you generate the table dynamically at the server end, it would be better to do the group with SQL or server end languages, and attach some class to the tr to identify the groups.

Hiding columns in table JavaScript

This script stops working the moment I add a table inside a table, so how to get it worked?
I don't need any jQuery solutions, I want pure JavaScript. Here's my script found on the Internet:
<script>
function show_hide_column(col_no, do_show) {
var stl;
if (do_show) stl = 'block'
else stl = 'none';
var tbl = document.getElementById('id_of_table');
var rows = tbl.getElementsByTagName('tr');
for (var row=1; row<rows.length;row++) {
var cels = rows[row].getElementsByTagName('td')
cels[col_no].style.display=stl;
}
}
</script>
Here's my HTML:
<table id='id_of_table' border=1>
<tr><td colspan="4"><table><tr><td></td></tr></table></td></tr>
<tr><td> 2</td><td> two</td><td> deux</td><td> zwei</td></tr>
<tr><td> 3</td><td> three</td><td> trois</td><td> drei</td></tr>
<tr><td> 4</td><td> four</td><td>quattre</td><td> vier</td></tr>
<tr><td> 5</td><td> five</td><td> cinq</td><td>fünf</td></tr>
<tr><td> 6</td><td> six</td><td> six</td><td> sechs</td></tr>
</table>
And here's my Form:
<form>
Enter column no: <input type='text' name=col_no><br>
<input type='button' onClick='javascript:show_hide_column(col_no.value, true);' value='show'>
<input type='button' onClick='javascript:show_hide_column(col_no.value, false);' value='hide'>
</form>
You can leverage the col tag and then the solution is straightforward using only vanilla JavaScript. The col tag has only a few CSS attributes, but visibility is one of them:
function show_hide_column( col_no, do_show ){
const table = document.getElementById( 'id_of_table' )
const column = table.getElementsByTagName( 'col' )[col_no]
if ( column ){
column.style.visibility = do_show?"":"collapse";
}
}
const btnHide = document.getElementById( 'btnHide' )
btnHide.addEventListener( "click", () => show_hide_column( 2, false ))
const btnShow = document.getElementById( 'btnShow' )
btnShow.addEventListener( "click", () => show_hide_column( 2, true ))
<table id='id_of_table' border=1>
<col class="col1"/>
<col class="col2"/>
<col class="col3"/>
<col class="col4"/>
<tr><td colspan="4"><table><tr><td></td></tr></table></td></tr>
<tr><td> 2</td><td> two</td><td> deux</td><td> zwei</td></tr>
<tr><td> 3</td><td> three</td><td> trois</td><td> drei</td></tr>
<tr><td> 4</td><td> four</td><td>quattre</td><td> vier</td></tr>
<tr><td> 5</td><td> five</td><td> cinq</td><td>fÜnf</td></tr>
<tr><td> 6</td><td> six</td><td> six</td><td> sechs</td></tr>
</table>
<button id="btnHide">hide French</button>
<button id="btnShow">show French</button>
References:
col
visibility on quirksmode
You could use children and check their tagName to make sure they're td's. Something like this:
function show_hide_column(col_no, do_show) {
var tbl = document.getElementById('id_of_table');
var rows = tbl.getElementsByTagName('tr');
for (var row = 0; row < rows.length; row++) {
var cols = rows[row].children;
if (col_no >= 0 && col_no < cols.length) {
var cell = cols[col_no];
if (cell.tagName == 'TD') cell.style.display = do_show ? 'block' : 'none';
}
}
}
Edit: Here's a working example: http://jsfiddle.net/3DjhL/2/.
Edit:
In fact, I've just remembered the rows and cols properties, which make it even simpler. See http://jsfiddle.net/3DjhL/4/ to see it in action.
function show_hide_column(col_no, do_show) {
var rows = document.getElementById('id_of_table').rows;
for (var row = 0; row < rows.length; row++) {
var cols = rows[row].cells;
if (col_no >= 0 && col_no < cols.length) {
cols[col_no].style.display = do_show ? '' : 'none';
}
}
}
Oh, and if you think the column numbers should start at 1 (which they don't), you'll have to offset that somewhere. For example at the top of show_hide_column():
col_no = col_no - 1;
The important thing here is the selector, it could be vanilla or jquery:
document.querySelectorAll('#yourtable tbody tr td:nth-child(1)').forEach(el=>el.style.display = 'none')
From the code above, the nth-child(1) selector has a 1-based index, there you define the column you want to hide ;)
I had a situation where it would have been a very big hassle to modify every single TD value and add the appropriate class name so I could toggle it. As a result I wrote some JavaScript to do that automatically. Please see the following code.
tbl = document.getElementById("Mytable")
classes = getClasses(tbl.rows[0]);
setClasses(tbl, classes);
toggleCol("col0");
toggleCol("col1");
function getClasses(row){
var cn = 0;
var classes = new Array();
for(x=0; x < row.cells.length; x++){
var cell = row.cells[x];
var c = new Column(cell.textContent.trim(), cell.offsetLeft, cell.offsetLeft + cell.offsetWidth, x);
classes[x]= c;
}
return classes;
}
function Column(name, left, right, cols) {
this.name = name;
this.left = left;
this.right = right;
this.cols = cols;
}
function setClasses(table, classes){
var rowSpans = new Array();
for(x=0; x < table.rows.length; x++){
var row = table.rows[x];
for(y=0; y < row.cells.length; y++){
var cell = row.cells[y];
for(z=0; z < classes.length; z++){
if(cell.offsetLeft >= classes[z].left && cell.offsetLeft <= classes[z].right){
cell.className = "col" + classes[z].cols;
}
}
}
}
}
function toggleCol(name){
var cols = document.getElementsByClassName(name);
for(x=0; x < cols.length; x++){
cols[x].style.display= (cols[x].style.display == 'none') ? '' : 'none';
}
}
In my example I take a look at the first row to set the top level header (In my example I had several who had colspans). It uses the offsetLeft and offsetWidth to determine the range of the top header (which in my cases has sub headers), so that all sub-columns would toggle with its parent.
Based on these values setClasses sets the appropriate classes to all the elements.
In my example I then toggle "col0" and "col1", so they would be invisible (Running the function again would make them visible again).

Categories