Hiding TR when TD contains specific class - javascript

I have the below Javascript code on my PHP page, I pass the table name and a variable to the function. The "ALL" portion of the code works fine, parses through the page and flips all of the CSS style display descriptors from 'none' to '' or back.
Where I'm running into issues is the "RED" portion. It is supposed to hide all TR which contain a TD of the class "RedCell" but I cannot seem to get this part working as intended. Please help.
JAVASCRIPT
function expandCollapseTable(tableObj, which)
{
if (which == 'ALL')
{
var rowCount = tableObj.rows.length;
for(var row=0; row<rowCount; row++)
{
rowObj = tableObj.rows[row];
rowObj.style.display = (rowObj.style.display=='none') ? '' : 'none';
}
return;
}
if (which == 'RED')
{
$('td.RedCell').find('td.RedCell').closest('tr').style.display = 'none';
return;
}
else
{
return;
}
}
CSS
.ResultTable td.RedCell{
background-color:#FF4747;
}
HTML BUTTONS AND EXAMPLE TABLE
<input type="button" value="Show/hide ALL" onclick="expandCollapseTable(TheTable, 'ALL')" />
<input type="button" value="Hide Red" onclick="expandCollapseTable(TheTable, 'RED')" />
<table id="TheTable" class="ResultTable" style="padding: 0px; background: #FFFFFF;" align="center">
<tr><td class="RedCell">2014-07-17 10:04</td><td>1998847</td><td>137717</td></tr>
<tr><td>2014-08-06 10:44</td><td>2009211</td><td>106345</td>
<tr><td class="RedCell">2014-07-31 16:47</td><td>2006727</td><td>138438</td>
So the first and third row would be hidden and second row left visible
CodePen version of code http://codepen.io/anon/pen/DrKLm

It should be:
$('td.RedCell', tableObj).closest('tr').hide();
The call to .find() was looking for another td.RedCell inside the first one.
Also, you can't use the .style property with jQuery objects, that's for DOM elements. To hide something with jQuery, use .hide() or .css("display", "none").
And you need to restrict your searching to within the given tableObj.
BTW, why aren't you using jQuery for the ALL option? That entire loop can be replaced with:
$("tr", tableObj).toggle();

Instead of going from the child up to the parent, use the jQuery :has selector to filter elements based on descendents.
$(tableObj).find('tr:has(td.RedCell)').hide();
In addition, you'll probably want to hide all of the cells only if none are already hidden. If any are hidden, you'll want to show those and keep the rest visible. Here's an example of that...
var rows = $(tableObj).find('tr:gt(0)'); // Skips the first row
if(rows.is(':hidden')) {
// Contains elements which are hidden
rows.show();
} else {
rows.hide();
}
The result would be:
function expandCollapseTable(tableObj, which) {
var rows = $(tableObj).find('tr:gt(0)');
if(which == 'RED') {
// First snippet
rows.has('td.RedCell').hide();
} else if(which == 'ALL') {
// Second snippet
if(rows.is(':hidden')) {
rows.show();
} else {
rows.hide();
}
}
}
http://codepen.io/anon/pen/xlmcK
Extra programming candy:
The second snippet could be reduced to rows[rows.is(':hidden')?'show':'hide']();

Two problems, the .find is saying to find descendents of the td.RedCell's that are td.RedCells.
There aren't any of those...
Then, use .css to set the style.
So this:
$('td.RedCell').closest('tr').css('display', 'none');

Related

For loop with eval not working

My first time writing my own javascript/jQuery for-loop and I'm running into trouble.
Basically, I have a series of divs which are empty, but when a button is clicked, the divs turn into input fields for the user. The input fields are there at the outset, but I'm using CSS to hide them and using JS/jQuery to evaluate the css property and make them visible/hide upon a button click.
I can do this fine by putting an id tag on each of the 7 input fields and writing out the jQuery by hand, like this:
$('#tryBTN').click(function(){
if ( $('#password').css('visibility') == 'hidden' )
$('#password').css('visibility','visible');
else
$('#password').css('visibility','hidden');
}
Copy/pasting that code 7 times and just swapping out the div IDs works great, however, being more efficient, I know there's a way to put this in a for-loop.
Writing this code as a test, it worked on the first one just fine:
$('#tryBTN').click(function() {
for(i = 1; i <= 7; i++) {
if($('#input1').css('visibility') == 'hidden')
$('#input1').css('visibility', 'visible');
}
});
But again, this only works for the one id. So I changed all the HTML id tags from unique ones to like id="intput1" - all the way out to seven so that I could iterate over the tags with an eval. I came up with this:
$('#tryBTN').click(function () {
for (i = 1; i <= 7; i++) {
if ($(eval('input' + i)).css('visibility') == 'hidden')
$('input' + i).css('visibility', 'visible');
}
});
When I put in the eval stuff - it doesn't work. Not sure what I'm doing wrong. A sample of the HTML looks like this:
<form>
<div class="form-group">
<label for="page">Description: Specifies page to return if paging is selected. Defaults to no paging.</label>
<input type="text" class="form-control" id="input7" aria-describedby="page">
</div>
</form>
You were forgetting the #:
$('#tryBTN').click(function () {
for (i = 1; i <= 7; i++) {
var el = $('#input' + i); // <-- The needed `#`
if (el.css('visibility') == 'hidden') {
el.css('visibility', 'visible');
}
}
});
#Intervalia's answer explains the simple error in your code (the missing #), and the comments explain why you should never use eval() unless you absolutely know it's the right tool for the job - which is very rare.
I would like to add a suggestion that will simplify your code and make it more reliable.
Instead of manually setting sequential IDs on each of your input elements, I suggest giving them all a common class. Then you can let jQuery loop through them and you won't have to worry about updating the 7 if you ever add or remove an item.
This class can be in addition to any other classes you already have on the elements. I'll call it showme:
<input type="text" class="form-control showme" aria-describedby="page">
Now you can use $('.showme') to get a jQuery object containing all the elments that have this class.
If you have to run some logic on each matching element, you would use .each(), like this:
$('#tryBTN').click( function() {
$('.showme').each( function( i, element ) {
if( $(element).css('visibility') == 'hidden' ) {
$(element).css( 'visibility', 'visible' );
}
});
});
But you don't need to check whether an element has visibility:hidden before changing it to visibility:visible. You can just go ahead and set the new value. So you can simplify the code to:
$('#tryBTN').click( function() {
$('.showme').each( function( i, element ) {
$(element).css( 'visibility', 'visible' );
});
});
And now that the only thing we're doing inside the loop is setting the new visibility, we don't even need .each(), since jQuery will do the loop for us when we call .css(). (Thanks #TemaniAfif for the reminder.)
So the code becomes very simple:
$('#tryBTN').click( function() {
$('.showme').css( 'visibility', 'visible' );
});

Changing properties of all <hr> html elements

In css I have set all the <hr> elements in my html to "display:none;" which works.
I have an onclick event listener set up to change the "display" to "block".
I use:
document.getElementsByTagName("hr").innerHTML.style.display = "block";
I get an error "Cannot read property 'style' of undefined".
Do it the following way:
var hrItems = document.getElementsByTagName("hr");
for(var i = 0; i < hrItems.length; i++) {
hrItems[i].style.display = 'block';
}
This is incorrect in two ways
getElementsByTagName gives you a list on elements and there is no method to operate on all elements, so you'll have to loop through all of them and add the required style individually.
innerHTML returns a string containing the mark up in an element but <hr> doesn't have any thing in it and the style property is on the <hr> itself.
var hrs = document.getElementsByTagName("hr");
for(var i = 0; i < hrs.length; i++) {
hrs[i].style.display = 'block';
}
Simple (and very effective) solution:
tag your body with a class-element
<body class="no_hr"> <article><hr/> TEXT Foo</article> <hr/> </body>
in css don't hide hr directly, but do
.no_hr hr {
display:none;
}
now define a second style in your css
.block_hr hr{
display:block;
}
in your buttons onClick, change the one and only body class from no_hr to block_hr
onclick() {
if ( document.body.className == "no_hr" ) {
document.body.className = "block_hr";
} else {
document.body.className = "no_hr";
}
}
This is a very charming solution, because you don't have to iterate over elements yourself, but let your browsers optimized procedures do their job.
For people who want a solution that doesn't require JavaScript.
Create an invisible checkbox at the top of the document and make sure that people can click on it.
<input type="checkbox" id="ruler"/>
<label for="ruler">Click to show or hide the rules</label>
Then tell the stylesheet that the <hr>s should be hidden by default, but should be visible if the checkbox is checked.
#ruler, hr {display:none}
#ruler:checked ~ hr {display:block}
Done. See fiddle.
getElementsByTagName() returns a node list, and therefore you must iterate through all the results. Additionally, there is no innerHTML property of an <hr> tag, and the style must be set directly on the tag.
I like writing these types of iterations using Array.forEach() and call:
[].forEach.call(document.getElementsByTagName("hr"), function(item) {
item.style.display = "block";
});
Or, make it even easier on yourself and use jQuery:
$("hr").show();

Jquery add using append and remove using .remove

I'm trying to make two buttons that acts as remove and add function first I have this:
HTML
<video id="localVideo" style="background-color:black"></video>
<div id="remoteVideos"></div>
Buttons
<button id="BtnOn">On</button>
<button id="BtnOff">Off</button>
Script:
$(document).ready(function() {
//$("#BtnOn").click(function() {
// $('#A').append("<div id='localVideo'>");
// $('#A').append("<div id='remoteVideos'>");
//});
$("#BtnOff").click(function() {
$("#localVideo").remove();
$("#remoteVideos").remove();
});
});
What I'm trying to do is remove the 2 div's and have the ability to return them, with the condition that you can only add them if they are missing and remove them if they are present, therefore limiting them to 1 add and 1 remove. How can I accomplish this?Any help suggestion is appreciated
You could check if the #localVideo element exists. Also, if they are the only elements in the #A element, you can remove them by calling $('#A').empty();.
$(document).ready(function() {
$('#BtnOn').click(function() {
if ($('#localVideo').length == 0) {
$('#A').append('<video id="localVideo" style="background-color:black"></video><div id="remoteVideos"></div>');
}
});
$('#BtnOff').click(function() {
if ($('#localVideo').length > 0) {
$("#localVideo").remove();
$("#remoteVideos").remove();
}
});
});
You could also consider hiding and showing the video elements, rather than adding and removing them.
Instead of using .append() and .remove(), you can change the CSS display property to none or initial, depending on whether you want the thing to be shown or not.
This way, you can then add an if statement like so:
$("#BtnOff").click(function() {
if('#localvideo').css('display') == 'none'){
//do nothing
} else {
$('#localVideo').css('display','none');
$('#remoteVideos').css('display','none');
}
});

How do I set the CSS for one instance of a class when the markup has multiple instances

I have a page with a content accordion with 8 items. I also have an h4 tag on the page outside of the accordion. I want to hide which ever content accordion item matches the text inside the h4 tag.
The text inside the h4 tag and the content accordion items might change so I need to use variables (I think).
Here is what I have so far:
var category = $('.leftColumnNav h4').html();
var topic = $('.contentAccordionItemTitle p').html();
if(topic === category){
$(".contentAccordionItemTitle").css("display", "none");
} else {
$(".contentAccordionItemTitle").css("display", "block");
}
What I have sort of works. It successfully hides the .contentAccordionItemTitle. Unfortunately it obviously hides all of them. I just want to hide the one that matches the h4 tag.
If it's needed I can probably create a JSFiddle example.
var category = $('.leftColumnNav h4').text();
$(".contentAccordionItemTitle").each(function() {
if ($(this).text() === category) { $(this).hide() }
})
var topic = $('.contentAccordionItemTitle p').html();
That line means you're getting all the p-tags. If you want to continue down this solution, you could use the jQuery each function -> http://api.jquery.com/each/
$(".contentAccordionItemTitle").css("display", "none");
} else {
$(".contentAccordionItemTitle").css("display", "block");
The $(".contentAccordionItemTitle") also gets all elements with this class.
You should use a loop, like jQuery each:
var category = jQuery('.leftColumnNav h4').html();
jQuery('.contentAccordionItemTitle p').each(function() {
if(jQuery(this).html() === category) {
jQuery(this).parent('.contentAccordionItemTitle').css('display', 'none');
} else {
jQuery(this).parent('.contentAccordionItemTitle').css('display', 'block');
}
This is assuming there is only one element that matches jQuery('.leftColumnNav h4')

How can I hide empty html table cells with jQuery?

I have a 5×7 HTML table. On many queries, there are fewer than 35 items filling the complete table.
How can I "hide" the empty cells dynamically in this case, using jQuery (or any other efficient way)?
Edit - Improved Version
// Grab every row in your table
$('table#yourTable tr').each(function(){
if($(this).children('td:empty').length === $(this).children('td').length){
$(this).remove(); // or $(this).hide();
}
});
Not tested but seems logically sound.
// Grab every row in your table
$('table#yourTable tr').each(function(){
var isEmpty = true;
// Process every column
$(this).children('td').each(function(){
// If data is present inside of a given column let the row know
if($.trim($(this).html()) !== '') {
isEmpty = false;
// We stop after proving that at least one column in a row has data
return false;
}
});
// If the whole row is empty remove it from the dom
if(isEmpty) $(this).remove();
});
Obviously you'll want to adjust the selector to fit your specific needs:
$('td').each(function(){
if ($(this).html() == '') {
$(this).hide();
}
});
$('td:empty').hide();
How about CSS empty-cells
table {
empty-cells: hide;
}
I'm voting for Ballsacian's answer. For some reason,
$('table#myTable tr:not(:has(td:not(:empty)))').hide();
has a bug. If you remove the outermost :not(), it does what you'd expect, but the full expression above crashes jQuery.

Categories