Show/hide table row if a child DIV is empty - javascript

I have a table with multiple entries. After each entry table row is an edit table row, with a column spanned cell, inside of which is a DIV which HTML is dynamically loaded into. The problem is that having all these empty table rows causes a lot of extra whitespace to appear on the page when it's rendered.
I understand I can't dynamically load HTML directly into the cell, so I have a DIV in it which I load the content into.
I want to hide any table row while the child DIV in it is empty, and show that table row once information has been dynamically loaded into the child DIV. This dynamically loaded information can also removed so I need it to be hidden again once it's empty again.
<table width="100%">
<tbody>
<tr>
<td>A</td>
<td>B</td>
<td>C</td>
</tr>
<tr style="display: none;">
<td colspan="3"><div></div></td>
</tr>
</tbody>
</table>
$("tr").each(function() {
if (this.children().filter(":empty").length) {
this.hide();
} else {
this.show();
}
});

The div isn't a child, it's a grandchild, thus children() won't find the divs. Use the context or find instead.
You are operating hide and show on the DOM element, not the jQuery element. You need to wrap it in jQuery first.
Therefore, run this code everytime you load something:
//find empty divs and hide it's tr
$("div:empty").closest('tr').hide();
//find non-empty divs and show it's tr
$("div:not(:empty)").closest('tr').show();
And look ma! No loops! No each! :D

You should use $(this) instead of this.
Reason being: $(this) is a JQuery object, which allows you to call JQuery methods like .children() and .filter(":empty") on it, whereas this is only a Javascript object...

Related

How exactly does this JQuery script work? and how can I modify it to select a specific object?

I am absolutly new in JavaScript and jQuery and I have the following problem.
I have the following jQuery script:
$(document).ready(function () {
$("thead.opening").click(function () {
$(this).next().slideToggle('slow', function () {
$(this).prev("thead.opening").toggleClass("active");
$("thead.opening").find(".imgAccordion").attr("src", "img/arrow.gif");
$("thead.active").find(".imgAccordion").attr("src", "img/arrow_down.gif");
});
return false;
});
});
and in my HTML I have something like this:
<table class="standard-table-cls table-header-cls">
<thead class="opening active">
<tr>
<th>
<img class="imgAccordion" src="img/arrow_down.gif"/>
Ricerca Flussi (la funzione e' consentita per flussi inferiori alle 300 fatture)
</th>
</tr>
</thead>
<tbody class="expanded">
<tr>
<td style="width: 100em;">
SHOW SOMETHING
</td>
</tr>
</tbody>
</table>
...........................................................
...........................................................
...........................................................
<table class="standard-table-cls table-header-cls">
<thead class="opening">
<tr>
<th>
<img class="imgAccordion" src="img/arrow.gif"/>
Ricerca Fatture
</th>
</tr>
</thead>
<tbody class="expanded" style="display: none;">
<tr>
<td style="width: 100em;">
SHOW SOMETHING ELSE
</td>
</tr>
</tbody>
<table>
As you can see in my code there is 2 different tables both having the same classes (standard-table-cls table-header-cls).
When I click on the thead of one of these table it seems to me that the previous script is perfromed (it is right or am I saying wrong assertion?).
I think so because this statment:
$("thead.opening").click(function () {.......
means something like: perform the body of the defined function() when the user click on any thead element having class=opening.
Is it my reasoning correct?
No my doubt (and also the related problem) is: how jQuery know what is the specific thead.opening clicked by the user (the one related to the first table or the one related to the second table)?
What exactly represent the $(this) element in the previous script? (it is the selected object or what?)
And finally, how can I modify the previous script to obtain the reference of the inner tbody of the same table of the thead.opening clicked?
Tnx
I'll keep this as short as possible but this is the scope in the current function. In elements, its an element. So for you?
$("thead.opening").click
runs a function. So the $(this) is the thread.opening that was actually clicked.
Post
this statment ... perform the body of the defined function() when the user click on any thead element having class=opening.
yes that is correct.
how JQuery know what is the specific thead.opening clicked by the user
the answer lies in: $(this).next().slideToggle('slow', function ()....
What exactly represent the $(this) element in the previous script?
the object which is clicked.
obtain the reference of the inner tbody of the same table of the thead.opening clicked
use something similar to the following in the click handler:
$(this).closest('.standard-table-cls').children('tbody')
reference: here and here
hope this helps.
When I click on the thead of one of these table it seems to me that
the previous script is perfromed (it is right or am I saying wrong
assertion?).
You are right
Is it my reasoning correct?
This is correct
What exactly represent the $(this) element in the previous script? (it
it the selected object or what?)
$(this) referes to the element invoking the function $("thead.opening").click(function () {});, so $(this) is equal to $("thead.opening"), where thead.opening is the exact element clicked (not the other thead.opening in your document).
And finnally, how can modify the previous script to obtain the
reference of the inner tbody of the same table of the thead.opening
clicked?
$(this).next() (which is used in your exemple) is the selector to target the tbody. $(this).next()means this (clicked thead), find next sibling element (tbody).
$("thead.opening") returns a array of elements that match the selector, in your case the two separate table headers that have the class opening added to them.
the .click() assigns a click event handler to each of the elements returned by the selector. In your case to both the table headers.
$(this) refers to element which invoked the event in the event handler.
The code $(this).next().slideToggle( is already referencing the next sibling of the thead - in your HTMLs case, the tbody.
You will have to change your script and change selectors. Current $("thead.opening") will for example select all <thead class="opening"> tags, so it would have to be similar to this:
$(document).ready(function () {
$("thead.opening").click(function () {
var thisThead = $(this);
var thisTbody = thisThead.next();
thisTbody.slideToggle('slow', function () {
thisThead.toggleClass("active");
thisThead.find(".imgAccordion").attr("src", thisThead.is('.active') ? "http://placehold.it/30/ffffff/000000" : "http://placehold.it/30/000000/ffffff");
});
});
});
Check this Fiddle with 2 tables.

Dynamically add css class to <tr> tag

I've three predefined class for <tr class="dynamicCSS"> tag. Those classes shall come one after another. Like -
<tr>
<td></td>
</tr>
<tr class="dynamicCSS"> //classA
<td></td>
</tr>
<tr class="dynamicCSS"> //classB
<td></td>
</tr>
<tr class="dynamicCSS"> //classC
<td></td>
</tr>
<tr class="dynamicCSS"> //repeat the above
<td></td>
</tr>
How can i do it?
You need some way of identifying the rows you want to add the classes to. (You can't use the same id value over and over again as you have in your question, so that won't work, but you could give them different id values.)
Once you have a way of identifying the tr elements in question, it's just a matter of setting the className property of those elements.
For instance, in your example you've identified the second, third, and fourth rows in the table. Assuming the table has the id "myTable", you can get the table's rows from its rows property, which is an HTMLCollection you can index into starting with 0:
var table = document.getElementById("myTable");
table.rows[1].className = "classA"; // second row
table.rows[2].className = "classB"; // third row
table.rows[3].className = "classC"; // fourth row
Note that that will wipe out any previous class the rows had. If you want to add a class, use += " classX" (note the space):
var table = document.getElementById("myTable");
table.rows[1].className += " classA"; // second row
table.rows[2].className += " classB"; // third row
table.rows[3].className += " classC"; // fourth row
In the above I've restricted myself to DOM functions that are present in just about all browsers, even older ones. On all major current browsers, rather than getElementById and the rows collection, you can use querySelector with any valid CSS selector expression that will identify the row you want to add a class to. You don't need it, necessarily, for what you've described, but it's good to know about it (and its cousin querySelectorAll, which returns a list of matching elements whereas querySelector returns just the first matching element).
Maybe you are looking for the nth:child css selector *1
For your example you can fiddle with it here:
http://jsfiddle.net/95N4E/
.myTable tr:nth-child(3n+1) {
background-color: gray;
}
.myTable tr:nth-child(3n+2) {
background-color: limegreen;
}
.myTable tr:nth-child(3n+3) {
background-color: steelblue;
}
And read how it works here:
*1 https://developer.mozilla.org/en-US/docs/Web/CSS/:nth-child
A simple way to add classes to tr elements would be to use jQuery.addClass():
jQuery("tr").addClass("myClass");
The selector passed into the jQuery call can also select nth children, for example to add a class to every third tr element:
jQuery("tr:nth-child(3n)").addClass("classC");

hiding part of table using javascript without changing the table layout

EDIT: okay I put everything in the script tag in a
$(document).ready(function) {
So now the evenTd's do hide.
I have a table and the code is below
<table>
<tr>
<td>itemOne</td>
<td class="evenTd">itemTwo</td>
</tr>
</table>
Now, I want it so that at the beggining, the first td is the only td which is visible (anything in evenTd should not be visible). After that, I want it so that when you click the first td (itemOne) then itemTwo slides and appears. So far I have
$(document).ready(function() {
$('.evenTd').hide();
});
and it is hiding the evenTd's, however, now the td's which don't have the evenTd class are taking up the entire screen. How do I make it so that the layout doesn't change?
If this is the entirety of your code, and this appears before the relevant elements (whether in the head or body elements, the problem is that the script is run before the DOM nodes exist.
Therefore, you can either place this in $(document).ready():
<script>
$(document).ready(function(){
$('.evenTd').hide();
});
</script>
Or place the script after the elements, in the HTML, upon which you want to act.
<body>
<table>
<tr>
<td>itemOne</td>
<td class="evenTd">itemTwo</td>
</tr>
</table>
<script>
$('.evenTd').hide();
</script>
</body>
Do bear in mind, though, that adding and removing individual table cells is likely to cause layout problems, it's probably better to hide the descendant elements of the relevant td, rather than the td itself.
For example, given the current HTML:
<table>
<tr>
<td>itemOne</td>
<td class="evenTd"><div>itemTwo</div></td>
</tr>
</table>
And:
$(document).ready(function(){
$('.evenTd').hide();
});
This gives: demo, causing the single visible td to take up the whole row-space.
Using the above HTML with the following jQuery:
$(document).ready(function(){
$('.evenTd div').hide();
});
This gives: demo, which still demonstrates layout-changes (because there's no visual content to show inside of the td), but the td remains visible (so it's a marginally-smaller change).
The following jQuery simply makes the content of the td 'hidden' (so it's not visible on the page, but is still 'there' taking up space in the document's flow):
$(document).ready(function(){
$('.evenTd div').css('visibility','hidden');
});
This gives: demo.
I would, however, prefer, certainly if this visibility is to be restored at some point, to add, or remove, a class on the td itself, and use CSS to address the specifics of each state:
$(document).ready(function(){
$('.evenTd').addClass('hidden');
$('tr').on('click', 'td.evenTd', function(){
$(this).toggleClass('hidden');
});
});
JS Fiddle demo.
You need to wait for DOM, before doing any Action:
<script type="JavaScript">
jQuery(document).ready(function(){
jQuery('td').hide().click(function(){
jQuery('td.visible').toggle().removeClass('visible');
jQuery(this).toggle().addClass('visible');
});
jQuery('td')[1].show().addClass('visible');
</script>
To show and hide elements you can use toggle() method.
<td id="cell32">cell data</td>
cell32 = document.getElementById("cell32");
cell32.style.display = "none";

Use Jquery to find the parent table, of a table, of a td

I am customising Sage CRM, so I have no control over the HTML that is written and can't add IDs or class's to the table layouts the CRM spits out. I want to hide a higher (not top) level table based on a users selection of a select dropdown. I can only get a jQuery selector hooked onto the title row of a table within the table I want to hide.
The DOM goes something like:
//Lots of other table structures above this in the DOM....
<table> <---- this is the table I want to show or hide based on the users selection
<tbody>
<tr>
<td>
<table>
<tbody>
<tr>
<td class="PANEREPEAT"> <---- this is the node I can get selector to
Valuation information
////
So I do the below client side javascript:
var val_information_screen;
$('.PANEREPEAT').filter(function () {
//Find the valuation information screen
return $(this).text() == 'Valuation information';
}).each(function () { //iterate through all of these (there should only be one!)
val_information_screen = $(this);
});
var sel_ofee_type = $('#ofee_type');
if (sel_ofee_type.val() == '006') {
val_information_screen.closest('table').parents("table:first").show();
} else {
val_information_screen.closest('table').parents("table:first").hide();
}
It does work, it just is not particularly beautiful. The bit that I really detest is below. Is there a better way to traverse up the DOM using jQuery?
val_information_screen.closest('table').parents("table:first").show();
val_information_screen.closest('table').parents("table:first").hide();
If you are sure that it has fixed structure, then you can use this,
$(td-selector).parents("table").eq(1).hide();
In your case,
val_information_screen.parents("table").eq(1).hide();
If your DOM (specifically starting from table you want to hide till the td you have as selector) is pretty much fixed, then the below selector can be used.
$('#element').parents('table').eq(1)

Jquery clone a table with specific row class

Hey how can I clone the table named teamselectiontable with just the table rows that have the class "chosen", and modify another table and replace its contents with the table rows found. But keeping the class names of "row" in the appended table.
<table id="teamselectiontable">
<tr class="chosen">content</tr>
<tr class="something">content</tr>
<tr class="something">content</tr>
<tr class="something">content</tr>
<tr class="something">content</tr>
<tr class="chosen">content</tr>
<tr class="chosen">content</tr>
</table>
To a table like below.
<table id="talentselection">
<tr class="row"></tr>
<tr class="row"></tr>
<tr class="row"></tr>
</table>
Thanks for any help.
$(".chosen").clone().attr("class","row").appendTo("#talentselection")
or if you want to replace the whole contents of the target table
$("#talentselection").html($(".chosen").clone().attr("class","row"));
Please note you need tds in your table markup for this to work
<tr><td class="chosen">content</td></tr>
Assuming I've understood what you're trying to do, you can use the clone method to clone the selected elements, and the appendTo method to append the clones into another element:
$("#teamselectiontable .chosen").clone().appendTo("#talentselection");
The elements in the original selection will be unaffected. Note that in its current form the above code will not clone any events bound to the matched elements. If you wanted to clone the elements with their events, just pass true into the clone method.
Update (see comments)
To change the class name on the cloned elements, you can use the removeClass and addClass methods:
$("#teamselectiontable .chosen")
.clone()
.appendTo("#talentselection")
.removeClass("chosen")
.addClass("row");

Categories