jQuery: Run function if each tr has class - javascript

I have a table where trs are being assigned class with js.
I have another div that I want to reflect it on. However, my each() function doesn't seem to be working properly.
I have the following JS:
$("table.result tr").each(function() {
if($(this).hasClass("red")) {
$("#color").addClass("red");
//bunch of other things
} else {
$("#color").addClass("green");
//bunch of other things
}
});
And this is my markup:
<table class="result">
<tr class="red">
<th>Name</th>
<th>Result</th>
</tr>
<tr class="red">
<td>John Doe</td>
<td>Pass</td>
</tr>
<tr class="red">
<td>Johnathan Doe</td>
<td>Pass</td>
</tr>
<tr class="red">
<td>Jane Doe</td>
<td>Fail</td>
</tr>
</table>
<div id="color"></div>
What I'm trying to do is, if all the trs have a class of red, only then do I want the div to have the class of red too else it should be green. But the jQuery is only testing it on the last tr whether it has the class or not.
But it doesn't seem to be working. It's probably a very small mistake but I cannot figure it out. Here's a jsfiddle: https://jsfiddle.net/okvv330L/6/
As you can see, since one tr does not have the class red, the div should be green. But it's only checking the last tr and basing it on that.
Thanks!

This is because the original styling is overriding the style of the added class.
The easiest solution would be to add higher specficity like
.red, #color.red {
background: red;
}
Update
What I'm trying to do is, if all tr's have the class red, then give the div a class of red else give it green.
$(function() {
$("#color").addClass("green");
$("table.result:not(:has(tr:not(.red))) + #color").addClass("red");
});
#color {
height: 50px;
width: 50px;
background: #ccc;
}
.green,
#color.green{
background: green;
}
.red,
#color.red {
background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<table class="result">
<tr class="red">
<th>Name</th>
<th>Result</th>
</tr>
<tr class="green">
<td>John Doe</td>
<td>Pass</td>
</tr>
<tr class="red">
<td>Johnathan Doe</td>
<td>Pass</td>
</tr>
<tr class="red">
<td>Jane Doe</td>
<td>Fail</td>
</tr>
</table>
<div id="color"></div>

It's working perfectly as it's adding the class .red in your div but it's just not taking the css as per the css specificity as id has greater specificity than class.
So, you may use:
#color.red{
background-color: #f00;
}
Or, you may use !important:
.red{
color: #f00 !important;
}
your jsfiddle
As per your comment, I have updated the fiddle. You may use like this:
$(function() {
if($("table.result tr.red").length == $("table.result tr").length) {
$("#color").addClass("red");
} else {
$("#color").addClass("green");
}
});

change your css.use important tag
.green {
background: green !important;
}
.red {
background: red !important;
}

Update: Since your want to assign the class red to #color only if all the trs has the class red
In that case using a loop will be wrong as it will always use the state of the last tr.
Also you have a problem with css specificity, where you have assigned a background color using ID property then that will have preference over the class rule you are assigning later, so you will have to make the class rule more specific by using a combination of the id rule and class rule.
$(function() {
var green = $("table.result tr").is(':not(.red)');
$("#color").toggleClass("green", green);
$("#color").toggleClass("red", !green);
});
#color {
height: 50px;
width: 50px;
background: #ccc;
}
.green,
#color.green {
background: green;
}
.red,
#color.red {
background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<table class="result">
<tr class="red">
<th>Name</th>
<th>Result</th>
</tr>
<tr class="red">
<td>John Doe</td>
<td>Pass</td>
</tr>
<tr class="red">
<td>Johnathan Doe</td>
<td>Pass</td>
</tr>
<tr class="red">
<td>Jane Doe</td>
<td>Fail</td>
</tr>
</table>
<div id="color"></div>

I got this working by using the following code:
var $rowCount = $('.result tr').length;
var $rowFill = 0;
$(".result tr").each(function() {
if($(this).is('.red')) {
$rowFill = $rowFill + 1;
}
});
if($rowFill == $rowCount) {
$('#color').addClass('red');
} else {
$('#color').addClass('green');
}
Since the each() was only testing the last row; I got it to match the count with the number of rows. So now, it seems to work fine.

Related

How to make expandable table cells hidden by default using jQuery/JavaScript, and click-able outside of a label?

I have this short piece of code that allows for sections of a table to be collapsed (they are like collapsible headers). This is neat, but I'm trying to make for the inverse to happen upon loading the page -- to be collapsed by default on load, but expandable when clicked. How would I go about doing this?
My present code, shown below, also features sections that only collapse when the words in the section are clicked, not when the section itself (outside of the words) are clicked. This is because I used labels to make the collapsible. Is there a way to make the entire row expandable/collapsible?
table {
width: 100%;
}
table,
tr,
th,
td {
border: 1px solid black;
border-collapse: collapse;
font-family: Arial;
}
[data-toggle="toggle"] {
display: none;
}
<table>
<thead>
<tr>
<th>Name</th>
<th>Number</th>
</tr>
</thead>
<tbody>
<tbody class="labels">
<tr>
<td colspan="2">
<label for="section">Click me!</label>
<input type="checkbox" id="section" data-toggle="toggle">
</td>
</tr>
</tbody>
<tbody class="hide">
<tr>
<td>Jack</td>
<td>100</td>
</tr>
<tr>
<td>Jill</td>
<td>300</td>
</tr>
</tbody>
</table>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
$(document).ready(function() {
$('[data-toggle="toggle"]').change(function() {
$(this).parents().next('.hide').toggle();
});
});
</script>
I'm trying to make for the inverse to happen upon loading the page --
to be collapsed by default on load, but expandable when clicked. How
would I go about doing this?
Simply add a line in your jquery above your toggle function and call on your .hide class selector and use .hide(); Then when you click it the toggle function fires.
also features sections that only collapse when the words in the
section are clicked, not when the section itself (outside of the
words) are clicked. This is because I used labels to make the
collapsible. Is there a way to make the entire row
expandable/collapsible?
Yes... Make your label display as block in your CSS file...
label {
display: block;
}
$(document).ready(function() {
$('.hide').hide();
$('[data-toggle="toggle"]').change(function() {
$(this).parents().next('.hide').toggle();
});
});
table {
width: 100%;
}
table,
tr,
th,
td {
border: 1px solid black;
border-collapse: collapse;
font-family: Arial;
}
[data-toggle="toggle"] {
display: none;
}
label {
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
<thead>
<tr>
<th>Name</th>
<th>Number</th>
</tr>
</thead>
<tbody>
<tbody class="labels">
<tr>
<td colspan="2">
<label for="section">Click me!</label>
<input type="checkbox" id="section" data-toggle="toggle">
</td>
</tr>
</tbody>
<tbody class="hide">
<tr>
<td>Jack</td>
<td>100</td>
</tr>
<tr>
<td>Jill</td>
<td>300</td>
</tr>
</tbody>
</table>
Several things going on here...
You were hiding your checkbox, which I don't think was your intent.
Check this example, where I fixed some things: https://jsfiddle.net/za73qf65/
Fixes include:
changing the name of your "hide" class to "hidable"
defaulting that "hidable" class to be display:none
unhiding your checkbox
changing your change() event handler to a click() (optional)
attaching your event handler to a button with an ID (you can vary that)
Point is, with my changes, your example works. You might want to tweak it for a more specific need.

hide/show tbody of dynamically created tables on click at thead

As you can see after you run the code, i have multiple tables, let us assume they were dynamically created with PHP. I try to hide/show the entire tbody of a table if i click at it's thead.
I could just give each table it's own id and write the jquery code for each table... but since the tables are dynamically created, i can't solve it like this.
The current version of my jquery script toggles all tbody's if i click on a thead, instead of only the thead of the table which i actually clicked.
My only idea to solve this would be to also create the jquery code dynamically (but im not sure if this will actually work), but before i try this, does someone know if there is an easier solution?
I thought about something like this:
$("this tbody").css("display","none");
So that it only selects the tbody of the thead which i actually clicked on.
var main = function()
{
$toggle = true;
$("thead").click
(
function()
{
if ($toggle)
{
$toggle = false;
$("tbody").css("display","none");
}
else
{
$toggle = true;
$("tbody").css("display","");
}
}
);
}
$(document).ready(main);
table, td {
border: 1px solid black;
}
td {
color: red;
display: block;
max-width: 120px;
white-space: nowrap;
overflow-x: auto;
background-color: blue;
}
th {
border: 1px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<thead>
<tr><th id="here1">First Table</th></tr>
</thead>
<tbody>
<tr><td>A</td></tr>
<tr><td>B</td></tr>
<tr><td>C</td></tr>
</tbody>
</table>
<table>
<thead>
<tr><th id="here1">Second Table</th></tr>
</thead>
<tbody>
<tr><td>A</td></tr>
<tr><td>B</td></tr>
<tr><td>C</td></tr>
</tbody>
</table>
First, instead of using $('tbody'), use this
Second, instead of managing variables for visibility, use toggle function
var main = function() {
$("thead").on("click", function() {
$(this).parents("table").find("tbody").toggle();
});
}
$(document).ready(main);
table,
td {
border: 1px solid black;
}
td {
color: red;
display: block;
max-width: 120px;
white-space: nowrap;
overflow-x: auto;
background-color: blue;
}
th {
border: 1px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<thead>
<tr>
<th id="here1">First Table</th>
</tr>
</thead>
<tbody>
<tr>
<td>A</td>
</tr>
<tr>
<td>B</td>
</tr>
<tr>
<td>C</td>
</tr>
</tbody>
</table>
<table>
<thead>
<tr>
<th id="here1">Second Table</th>
</tr>
</thead>
<tbody>
<tr>
<td>A</td>
</tr>
<tr>
<td>B</td>
</tr>
<tr>
<td>C</td>
</tr>
</tbody>
</table>
try with
$(this).parent().find('tbody').css("display","none");
you can use .next() https://api.jquery.com/next/
$(this).next("tbody").css("display","none");
or better yet use toggle https://api.jquery.com/toggle/
$(this).next("tbody").toggle();
<table class="table" id="item"style="display:none;">
<tbody style="height:0px;width:82%; display:table;"></tbody>
</table>
and using script
<script>`enter code here`
document.getElementById("item").style.display = "block";
</script>

Highlighting Table Rows

I have a dynamically built table that ends up with the below code (with example values):
<table id="patientTable" class="display" cellspacing="0" width="100%">
<thead id="TableHeader">
<tr>
<th>Value1</th>
<th>Value2</th>
<th>Value3</th>
</tr>
</thead>
<tbody id="tableContent">
<tr class="clickable row_0" onclick="selectPatient(10001);" id="10001" style="background: #FFF;">
<td class="tableContent">Value1</td>
<td class="tableContent">Value2</td>
<td class="tableContent">Value3</td>
</tr>
</tbody>
</table>
I am trying to highlight the row that is been hovered over using the below CSS:
.clickable :hover {
background-color: #CCC;
}
For some reason, this changes the background of what would be the "<td>" element, for example, will just highlight Value1, Value2 or Value3 rather than the entire row.
I have tried (to no avail) to use:
.clickable tr:hover {
background-color: #CCC;
}
.clickable:hover {
background-color: #CCC;
}
.tr:hover {
background-color: #CCC;
}
.tr :hover {
background-color: #CCC;
}
I find this unusual behaviour, as it appears to work for everyone else on every other example i've seen..
Worth Mentioning: The table is build from a complex system, that basically performs an AJAX request, which performs a PHP database query, takes the values, throws them into a JSON array, passes them back to JS, re-parses the array as JSON, loops through and creates the table, then outputs it. Could the JS be causing the issue?
The class name ".clickable", "row_#" (where # is a number) and the ID for the table row need to stay, as they are used in future functions and provide me with a way to identify each row individually.
One solution is to apply the hover on child elements td's when hover on parent tr:
.clickable:hover td {
background-color: #CCC;
}
<table id="patientTable" class="display" cellspacing="0" width="100%">
<thead id="TableHeader">
<tr>
<th>Value1</th>
<th>Value2</th>
<th>Value3</th>
</tr>
</thead>
<tbody id="tableContent">
<tr class="clickable row_0" onclick="selectPatient(10001);" id="10001" style="background: #FFF;">
<td class="tableContent">Value1</td>
<td class="tableContent">Value2</td>
<td class="tableContent">Value3</td>
</tr>
</tbody>
</table>
This works (from your question) :
.clickable:hover {
background-color: #CCC;
}
but why is there nothing happening when you hover then ?
because this rule is overwritten by the inline style: style="background: #FFF;"
Hint : NEVER write inline style (except if you REALLY need it)
if you remove style="background: #FFF;" everything will be fine.
Working example :
.clickable {
background-color: #FFF;
}
.clickable:hover {
background-color: #CCC;
}
<table id="patientTable" class="display" cellspacing="0" width="100%">
<thead id="TableHeader">
<tr>
<th>Value1</th>
<th>Value2</th>
<th>Value3</th>
</tr>
</thead>
<tbody id="tableContent">
<tr class="clickable row_0" onclick="selectPatient(10001);" id="10001">
<td class="tableContent">Value1</td>
<td class="tableContent">Value2</td>
<td class="tableContent">Value3</td>
</tr>
<tr class="clickable row_1" onclick="selectPatient(10002);" id="10002">
<td class="tableContent">Value1</td>
<td class="tableContent">Value2</td>
<td class="tableContent">Value3</td>
</tr>
</tbody>
</table>
Edit :
For more information about which CSS rule will have priority over others, see this article on MDN : https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity
You can't colour table rows. Colour the table cells (th and td) instead, using the direct child selector (>).
Edit: Apollo (below) is right: Of course you can colour table rows, but if you want to colour the row with a hover, you need this (just like the answer that was given before):
tr:hover > td,
tr:hover > th {
background-color:#ccc;
}

Is there a way to hide a data cell based on a specific value using just HTML/CSS?

For example I have this code:
<table>
<caption>Test</caption>
<tr>
<th>Values</th>
<td>$100</td>
</tr>
<tr>
<th>Initial value</th>
<td class="results"></td>
</tr>
</table>
Is there a way to hide the cells that are equal to $0 using HTML/CSS only?
Let's say instead of $0 I have a variable called fee that can be a variety of values: $0, $20, $100, etc.
For example:
<script>
var fees = ["$0", "$20", "$100"];
document.querySelector('.results').innerHTML = fees[1];
</script>
Is there a way to check what value it is and if it is found to be $0 can I then hide it?
My CSS is:
table{
border-width: 1px;
border-style: solid;
border-collapse: separate;
width: 400px;
}
#test{
empty-cells: show;
margin-bottom: 20px;
}
tr, th, td{
border-width:1px;
border-style: solid;
}
.results {
display: none; // I want this to only display none when fees = $0
}
TL;DR: It's possible. Look for the last solution in my answer, or check this blog:
Conditional formatting with pure css
I am assuming you do not want to hide the cell, but only its value. Hiding a cell does not make sense in a table since it would potentially change the layout, also any cell borders etc would also be hidden - probably not what you want.
Now CSS does not have any selectors based on element text content. But it does support attribute value selectors. So, you could change your code to be:
<table>
<caption>Test</caption>
<tr>
<th>Values</th>
<td><input value="$100"/></td>
</tr>
<tr>
<th>Initial value</th>
<td><input value="$0"/></td>
</tr>
</table>
And use a rule like
input[value="$0"] {
display: none;
}
You could even make the inputs not behave like inputs by adding a disabled attribute so they aren't editable.
If you don't want to use input elements, you could consider using spans instead and use a "data-value" attribute, and try if browsers respect that:
<table>
<caption>Test</caption>
<tr>
<th>Values</th>
<td><span data-value="$100">$100</span></td>
</tr>
<tr>
<th>Initial value</th>
<td ><span data-value="$0">$0</span></td>
</tr>
</table>
The css woudl be:
td > span[data-value="$0"] {
display: none;
}
Of course the drawback of this is that you would have to add the value twice (once as text content, once as attribute), and you need to generate an inner span element which feels a bit ugly.
Alternatively you could try to add a class attribute that includes the value and create a class selector:
<table>
<caption>Test</caption>
<tr>
<th>Values</th>
<td ><span class="value100">$100</span></td>
</tr>
<tr>
<th>Initial value</th>
<td ><span class="value0">$0</span></td>
</tr>
</table>
and the css would be:
td span.value0 {
display: none;
}
Of course the drawbacks are the same as with the previous method - you have to generate the value twice, once as text content and once as classname, and you need to add the inner span.
EDIT: dollar char is not valid in css classnames, so I removed it.
EDIT2: It turns out there is a way to do it without duplicating the value as both text and attribute. As a bonus, it turns out you don't need the inner span either if we rely on the :after pseudoclass (since it is that class that gets hidden, not the cell itself):
<table border="1">
<caption>Test</caption>
<tr>
<th>Values</th>
<td data-value="$100"></td>
</tr>
<tr>
<th>Initial value</th>
<td data-value="$0"></td>
</tr>
</table>
Using this css:
td:after {
content: attr(data-value);
}
td[data-value="$0"]:after {
content: "";
}

jQuery does :hover work for td elements?

I have a HTML Table with a hidden infobox in one of the td elements.
<style type="text/css">
.infobox{
display: none;
background-color: #FFDB8F;
font-size: 11px;
}
td {
border: 1px solid;
width: 90px;
height: 84px;
}
</style>
<table>
<tr>
<td>foobar</td>
<td>foobar</td>
<td class="hover">hover me</td>
<td class="hover">hover me</td>
<td colspan="2"><div class="infobox">The terms foobar, fubar, or foo, bar, baz and qux (alternatively, quux) are sometimes used as placeholder names (also referred to as metasyntactic variables) in computer programming or computer-related documentation.</div></td>
</tr>
<tr>
<td>foobar</td>
<td>foobar</td>
<td class="hover">hover me</td>
<td class="hover">hover me</td>
<td>foobar</td>
<td>foobar</td>
</tr>
</table>
I want to show this infobox when the user hovers over certain td elements. So tried this:
$('.hover').hover(function() {
$('.infobox').show();
},
function() {
$('.infobox').hide();
}
});
And this:
setInterval(function() {
var $sample = $(".hover");
$sample.each(function(index) {
if ($(this).is(":hover")) {
$('.infobox').show();
}
else {
$('.infobox').hide();
}
});
}, 200);
Both did not work for td elements. What am I missing? Or does .hover() simply not work for td elements?
The problem seems to be a typo, you have an extra } on your code.
$('.hover').hover(
function() {$('.infobox').show();},
function() {$('.infobox').hide();}
} // <-- remove this
);
Except for that, it seems to be working fine.
DEMO
extra } in you hover function. Please look your console before asking question.
$('.hover').hover(
function() {$('.infobox').show();},
function() {$('.infobox').hide();}
);
See fiddle here

Categories

Resources