Hide tr (table row) with text content - javascript

I'm trying to hide a table row with javascript and css.
I have to admit that I'm still a beginner, so it's likely that I'll ask some stupid questions.
I want to hide a table row that somewhere in a td contains the text 'banana'.
Hopefully someone can help me out, thanks!
I've tried different kinds of code I found on the internet, but can't get anything working. This is what I got so far.
if(document.getElementsByTagName('tr').contains('banana'))
{
document.getElementsByTagName('tr').style.display = 'none';
}

Problem you have is you seem to be thinking in terms of jQuery. JQuery does loops under the hood. Since you are not in jQuery world, you need to do the loops yourself over the collection.
Select the rows
loop over the rows
Read the text
Check if text as match
if it does, hide it
// select all the rows
const rows = document.querySelectorAll('tr');
// loop over the rows
rows.forEach( function (row) {
// get the text of the row
var text = row.textContent; // case insensitive use .toLowerCase()
// see if it is in the string
if (text.includes('banana')) {
// add class to hide the row
row.classList.add('hidden')
}
})
.hidden {
display: none;
}
<table>
<tbody>
<tr>
<td>apple</td><td>$1.00</td>
</tr>
<tr>
<td>pear</td><td>$1.00</td>
</tr>
<tr>
<td>banana</td><td>$1.00</td>
</tr>
<tr>
<td>strawberry</td><td>$1.00</td>
</tr>
</tbody>
<table>
How will this fail? When the text joins between cells there is no whitespace so you can make matches that are not there. Is you search for something that is partial sting in another word that can also be wrong.
Other option you have is instead of looping over the rows, you loop over the cells. And if there is a match in the td, you hide the parent.

Instead of getting tr element you can get all td element and perform the following:
var tdcollection = document.getElementsByTagName('td');
for (var i = 0; i < tdcollection.length; i++) {
if (tdcollection[i].innerText.indexOf("banana") >= 0) {
tdcollection[i].parentElement.style.display = 'none';
}
}
<table>
<tr><td>banana</td><td>test1</td></tr>
<tr><td>grape</td><td>test2</td></tr>
</table>

Related

Remove first TD of a TR Table in javascript

I am trying to remove a td at runtime using Javascript only (no JQuery intended). Here is my table :
<table id = "tab">
<tr>
<td>
test 1
</td>
<td>
test 2
</td>
<td>
test 3
</td>
</tr>
</table>
Here is what I tryied :
function removeFirstTD() {
var element = document.getElementById("tab");
element.removeChild(element.firstChild);
}
Note that this function works and I execute it by doing this :
<body onload = "removeFirstTD();">
<!-- the tab is here -->
</body>
The problem is that it seems to erase the <tr> because I didn't scope the tr before requesting remove the td. May someone help me doing this please ?
Maybe the simplest way is to use HTMLTableElement Interface:
function removeFirstTD() {
var element = document.getElementById("tab");
element.rows[0].deleteCell(0);
}
A live demo at jsFiddle.
Use can also use querySelector. It picks the first element that matches it like this;
function removeFirstTD() {
var element = document.querySelector("#tab tr td");
element.remove();
}
Go down one more level?
element.firstChild.removeChild(element.firstChild);
Due to white space (between the table and tr, and tr and td) this creates TEXTNODES which will be the first children, you would have to be more specific:
function removeFirstTD() {
var element = document.getElementById('tab');
var firstRow = element.getElementsByTagName('TR')[0];
var firstColumn = firstRow.getElementsByTagName('TD')[0];
firstColumn.remove();
}
But you might find this simpler and more reliable:
function removeFirstTD() {
document.querySelector('#tab tr td').remove();
}
You're close. td elements belong to the tr elements (and technically the tr elements should belong to a tbody element, not the table directly). You need to get the tr elements then find their first children.
function removeFirstTD() {
var element = document.getElementById("tab");
var tr = element.getElementsByTagName('tr');
var j = tr.length;
while (j--){
tr[j].removeChild(tr[j].firstChild);
}
}
Note that firstChild might be whitespace or some other entity that is no the first td element, and you should add a check for that before removing that child.
<table class="u-full-width">
<thead>
<tr>
<strong><td>Joke</td></strong>
</tr>
</thead>
<tbody>
<tr>
<td>This is a joke</td>
</tr>
</tbody>
</table>
I'm adding this to give a step by step procedure for beginners like me looking for this answer.
Let's say above is how our table looks
First, get a DOM reference to the table body let tbody = document.querySelector('u-full-width').getElementsByTagName('tbody')
The above statements return a HTML Collection. So, we take the zero index of that collections tbody = tbody[0]
tbody.removeChild(tbody.firstElementChild) firstElementChildignores text and comment nodes

Finding a row with a cell with a specific value

I have to mark all rows in a table (and later change the code to delete the rows).
The table structure looks like:
<table class="table table-striped table-condensed" id="buckettable">
<thead>
...cut out
</thead>
<tbody>
<tr class="success">
<td><input class="fld-bucketno" type="checkbox" name="bucket" value="158bf61f-8f66-4dee-9ff6-b9d1f6d4b840" /></td>
<td class="text-right">
<a class="bucketNo" href="/Sim/Staging/1212">1212</a>
</td>
What I am interested in is the value of the anchor in the td - second last line.
I get a json list of id's to delete. First I mark them, then change the code to delete them. That is the idea, at least. Mind me - I know a lot of programming, but Javascript is an unknown land for me ;)
My code so far is:
success: function (resp) {
var table = $('#buckettable').find('tbody')[0];
var length = resp.length;
for (var i = 0; i < length; i++) {
var bucketNo = resp[i];
var rows = table.children.length;
for (var j = 0; j < rows; j++) {
var row = table.children[j];
var bucket = row.find('.bucketNo').text();
if (bucket == bucketNo) {
alert(bucket);
}
}
}
$('#cleanup').modal('hide');
and I fail to filter the rows. I am open to any sensible other approach - hopefully it teaches me a lot.
In the above code I manage to get the row... but then the find('.bucketNo') fails with an aexception that Object # has no method find.... which I find funny because I use that on a form earlier. Pointers to documentation VERY welcome, especially in addition to an answer.
If there is a better way to do that tell me. I was told that search by ID is faster (obviously) but somehow I am not sure - should I set a coded ID (bucket-xxx, xxx being the number) on every row?
There is a much simpler way of doing this.
var targetBucketNo = 1212;
$('#buckettable a.bucketNo')
.filter(function(item) {
return item.text() == targetBuvketNo;
})
.parent()
.remove();
To explain in more detail. The following will get the anchors with the bucketNo class that are inside your #buckettable table.
$('#buckettable a.bucketNo')
Filter will filter the results for ones that have the target bucket number
.filter(function(item) {
return item.text() == targetBuvketNo;
})
Remove will remove the elements
.remove();
You can replace .remove() with .addClass('your-class-name') if you wanted to add a class instead. This would add it to the td element so you should add .parent() before addClass.
You are accessing the native Javascript children, hence find() is not a function. However you can skip around a lot of the native functions you're using by using the jQuery filter method:
var $aTag = $('#buckettable').find('tbody td a.bucketNo').filter(function() {
return $(this).text() == bucketNo
});
alert($aTag.text());
You can also loop all links with the class "bucketNo" and then look if the ID is in your array. After this get the containing TR and delete it or add a class or something:
var resp = [2323,5656]
$('a.bucketNo').each(function() {
if( resp.indexOf( parseInt($(this).text()) ) != -1 )
$(this).closest('tr').addClass('del');
});
http://jsfiddle.net/44cEt/

jQuery to select elements based on the text inside them

How to select a tag having a specific text inside it and nothing else? For example if I have the following:
<table>
<tr>
<td>Assets</td><td>Asset</td>
</tr>
<tr>
<td>Play</td><td>Players</td><td>Plays</td>
</tr>
</table>
Is there any way that I may select the <td>Asset</td> and nothing else. I tried it with contains i.e. $("table tr td:contains(Play)") but it returns all the tds in the second tr (as it should). Whereas I just want <td>Play</td>.
Is there any way to achieve this, like there's a way to select elements based on their attributes. Is there any way to select elements based on the text inside them?
How about that:
var lookup = 'Asset';
$('td:contains('+ lookup +')').filter(function() {
return $(this).text() === lookup;
});
Demo
Try before buy
Try something like this :
$("table tr td").filter(function() {
return $(this).text() === "Play";
})
If it was an input field you can specify something similar, but a little more exact with $('input[name~="Plays"]) so that it would filter out every other word, leaving the value isolated.
Other than that, the only way I know of doing this with a table is with what you had, but also throwing a conditional statement to check the text inside them.
Here is my version of accomplishing this:
http://jsfiddle.net/combizs/LD75y/3/
var play = $('table tr td:contains(Play)');
for (var i = 0, l = play.length; i < l; i++) {
if ($(play[i]).text() === "Play") {
// your script to modify below
$(play[i]).css({"color" : "red"});
}
}

How to modify HTML table with JavaScript to increase rowspan, without causing reflow?

To change HTML table so that some cell has given rowspan="n" (to increase rowspan) you have to delete n cells below the one that is getting extended.
The original HTML source (HTML structure) looks like this
<table border="1">
<tr id="1"><td>1</td><td>Zubenelgenubi</td></tr>
<tr id="2"><td>2</td><td>Algorab</td></tr>
<tr id="3"><td>3</td><td>Almach</td></tr>
<tr id="4"><td>4</td><td>Alula_Borealis</td></tr>
<tr id="5"><td>5</td><td>Rigil_Kentaurus</td></tr>
<tr id="6"><td>6</td><td>Menkent</td></tr>
</table>
and I like to transform it to something like this:
<table border="1">
<tr id="1"><td>1</td><td>Zubenelgenubi</td></tr>
<tr id="2"><td>2</td><td>Algorab</td></tr>
<tr id="3" rowspan="3"><td>3</td><td>Almach</td></tr>
<tr id="4"> <td>Alula_Borealis</td></tr>
<tr id="5"> <td>Rigil_Kentaurus</td></tr>
<tr id="6"><td>6</td><td>Menkent</td></tr>
</table>
Unfortunately SO formatting doesn't support tables, neither in Markdown, nor in HTML.
Is it possible to do it without causing unnecessary reflow? I mean here something better than simply
for (var i = 0; i < numlines; i++) {
...
if (i === 0) {
td.rowSpan = numlines;
...
} else {
tr.deleteCell(0); // or td.parentNode.removeChild(td);
}
}
which I think causes reflow after each iteration.
When adding elements one can use DocumentFragment; what to do when modifying number of elements at once?
Edit: added 03-05-2011
A solution using Range object (the W3C DOM version)
var range = document.createRange();
range.setStartBefore(document.getElementById(start+''));
range.setEndBefore(document.getElementById(start+numlines+''));
var fragment = range.cloneContents();
for (var i = 0; i < numlines; i++) {
var rownum = start + i;
var row = fragment.getElementById(rownum.toString()); // not always work
var td = row.firstChild;
if (i === 0) {
td.style.backgroundColor = 'yellow';
td.rowSpan = num.toString();
} else {
td.parentNode.removeChild(td);
}
}
range.deleteContents();
var rowAfter = document.getElementById(start+num+'');
rowAfter.parentNode.insertBefore(fragment, rowAfter);
Note that for some reason fragment.getElementById didn't work for me, so I had to cheat knowing what nodes are there.
deleteContents + insertBefore is needed because table.replaceChild(range, fragment); does not work, unfortunately (where table is element from which range was extracted).
Try to make the table element display:none
before the loop and restore the
display after.
Another option would be to assign
fixed dimensions and use
overflow:hidden for the the time of loop body.
This should isolate update tree by
the table only. Theoretically.
And the last is to compose HTML of
the table and replace the table as
whole - this will be made in single
transaction.

Odd DOM Problem with Firefox

I'm experiencing an odd problem when trying to navigate through a table's rows and cells in a while loop using javascript. I'm using Firefox 3.5.7 on Win7 with Firebug enabled.
I have this markup:
<table>
<tbody>
<tr id='firstRow'><td>a</td><td>b</td><td>c</td></tr>
<tr><td>a</td><td>b</td><td>c</td></tr>
<tr><td>a</td><td>b</td><td>c</td></tr>
</tbody>
</table>
And this javascript:
var row = document.getElementById('firstRow');
console.log(row); // Row call 1
while (row) {
console.log(row); // Row call 2
row = row.nextSibling;
}
The problem I'm having is that on the line commented "Row call 1", Firebug is outputting
<tr id='firstRow'>
as expected. However, in the while loop, Firebug is giving me
<tr id='firstRow'>
<TextNode textContent="\n">
It is giving me different output for the exact same row, even immediately after the while loop begins executing and nothing else touched the row. For subsequent rows, it of course does not have id='firstRow' as an attribute.
The bigger problem this is giving me is that if I'm in the while loop, and I want to access a particular cell of the current row using row.cells[0], Firebug will give me an error that row.cells is undefined.
I want to know if someone could shed some light on this situation I am experiencing.
Firefox is picking up the whitespace between your tr elements as an additional node. Simply add a test that the node is indeed a tr before doing anything with it:
var row = document.getElementById('firstRow');
console.log(row); // Row call 1
while (row) {
if(row.nodeName == "TR"){
console.log(row); // Row call 2
}
row = row.nextSibling;
}
Note that the text nodes have a nodeName of #text and that nodeName will always return the element name in all caps regardless of how you have it in your document.
The TextNode is correct, because you do have that after the </tr>.
A simple workaround is to skip those textnodes - by either counting or testing if
row.tagName == 'TR'
Use the tbody.rows collection. It's simpler:
var row = document.getElementById('firstRow');
console.log(row); // Row call 1
var tbody = row.parentNode;
var rows = tbody.rows;
for (var i=row.rowIndex+1; i<rows.length; i++) {
row = rows[i];
console.log(row); // Row call 2, 3 ...
}
For more info, see http://msdn.microsoft.com/en-us/library/ms537484%28VS.85%29.aspx
(or just google rowIndex)
EDIT: If the table also contains thead and/or tfoot then it might be more appropriate to use row.sectionRowIndex

Categories

Resources