Hiding container if all children are hidden in Angular - javascript

I am creating a number of tables dynamically, which all have a number of rows that are also created dynamically using Angular.
My goal is to have each table hidden if there are no visible rows in that table's tbody.
<table ng-repeat="package in listOfPackages" ng-if="this.getElementsByTagName('tbody')[0].childNodes.length > 0 ">
<tbody>
<tr ng-repeat="thing in package.things" ng-if="thing.status === 'interesting'">
<td>{{thing.someInfo}}</td>
<td>{{thing.someOtherInfo}}</td>
</tr>
</tbody>
</table>
The line ng-if="this.getElementsByTagName('tbody')[0].childNodes.length > 0" seems to be my problem - I do not know the proper way to find an element's own children, and check how many it has visible.
Is there any possible way to do this in angular?

create a function in your controller something like
$scope.showPackageTable = function (package) {
var toShow = false;
for (var thing in package.things) {
if (thing.status === 'interesting') { toShow = true; }
}
return toShow;
}
then you can use that in your html ng-if="showPackageTable(package)"

Related

Jquery Toggle Table Column Using a Better Method

I have a table with around 30 columns and the idea is to let the user select which columns to be hidden or shown. The reason for this is to let them select which columns will be visible when they print.
To tackle this problem, I have assigned a class name to each column and i'm using jQuery's toggle function. This works fine, but I was wondering if there is a better way to go about it that is more efficient and cleaner than what I am currently using. I have a separate function for each column and my code looks like this:
jQuery
function tablecolumn1toggle(){
$(".column1").toggle();
}
function tablecolumn2toggle(){
$(".column2").toggle();
}
function tablecolumn3toggle(){
$(".column3").toggle();
}
HTML Simplified
toggle column 1
toggle column 2
toggle column 3
<table class="table table-bordered" id="points_table">
<tbody>
<tr>
<th class="column1>Route</th>
<th class="column2">Location</th>
<th class="column3>Track</th>
</tr>
</tbody>
</table>
and so on..
I am using a button to call each toggle function, I will use checkboxes once I have the basic code working. So, is there a way for me to cut down the amount of code?
EDIT: Thank you all for your answers, it was really hard to pick a single answer but i'm grateful for all your input.
If you want to do it dynamically using checkboxes, add a data property to the checkbox
<input class='toggleColumns' type="checkbox" data-target="column1" />
<input class='toggleColumns' type="checkbox" data-target="column2" />
<input class='toggleColumns' type="checkbox" data-target="column3" />
<input class='toggleColumns' type="checkbox" data-target="column4" />
then add a change event on the checkbox:
$('.toggleColumns').on('change', function (e) {
// get the target for this checkbox and toggle it
var tableColumn = $(e.currentTarget).data('target');
$('.' + tableColumn).toggle();
});
Here is working fiddle: https://jsfiddle.net/9Ls49w97/
A bit of a late addition, but to add one more alternative: if you have multiple setups of this kind and you don't want to add classes each time, you can show or hide a column with something like $('tr *:nth-child(' + (ColumnIndex + 1) + ')', table).toggle();. Especially if you change the column order in the future, the class approach can come to bite you.
One step further, is not to define the checkboxes beforehand, but have JQuery create them on the fly. This is also easier in maintaining the page and with the added benefit that you can assign the column index while creating the input objects and don't have to add any special attributes in design time.
All in all, the html would be as light as possible (no classes or properties) and doesn't have to be maintained. An example where the checkboxes are added in a div:
var table = $('table'); //add an id if necessary
var cols = $('th', table); //headers
var div = $('<div>'); //new div for checkboxes
cols.each(function(ind){
$('<label>').text($(this).text()).append(
$('<input type="checkbox" checked=true>') //create new checkbox
.change(function(){
$('tr *:nth-child(' + (ind + 1) + ')', table).toggle();
})
).appendTo(div);
});
table.before(div); //insert the new div before the table
Fiddle
/* number is a parameter now */
function tablecolumntoggle(i){
$(".column"+i).toggle();
}
/* example to iteratly call */
for (var i = 1; i <= 3; i++) {
tablecolumntoggle(i);
};
Here's one way to make it simpler.
Give each button a data-col value and the matching column element(s) the same data-col value, then they can be paired in a simple function:
<button data-col='column1'>toggle</button>
<button data-col='total'>toggle</button>
<button data-col='other'>toggle</button>
<div class="col" data-col="column1">
column 1
</div>
<div class="col" data-col="total">
total column
</div>
<div class="col" data-col="other">
other
</div>
and code
$(function() {
$("button[data-col]").on("click", function() {
var col = $(this).data("col");
$(".col[data-col='" + col + "']").toggle();
});
})
Simple fiddle demo: https://jsfiddle.net/bb1mm0cp/
You Pass number 1,2,3 function
Try this
function tablecolumn1toggle(id){
$(".column"+id).toggle();
}
function call like this
tablecolumn1toggle(1); or
tablecolumn1toggle(2); or
tablecolumn1toggle(3);
OR
function tablecolumn1toggle(colum_name){
$(colum_name).toggle();
}
function call like this
tablecolumn1toggle(column1); or
tablecolumn1toggle(column2); or
tablecolumn1toggle(column3);

Keep rows with certain values always at the bottom while sorting in jquery tablesorter plugin

I'm using JQuery Table sorter plugin(http://tablesorter.com/docs/) in my application it works great but I would like to exclude certain rows which has N/A for the clicked column while sorting and keep them always at the end.
As far as i have checked if we put elements in tfoot it will always remains at the bottom. But i wanted to display those rows initially only when sorting happens I would like to move them at the end.
Below is my HTML
<table id="myTable" class="tablesorter">
<thead>
<tr>
<th>Code</th><th>Name</th><th>Count</th><th>Percentage</th>
</tr>
</thead>
<tbody>
<tr>
<td>1011</td><td>Cheif Executives</td><td>2385</td><td>20%</td>
</tr>
<tr>
<td>1012</td><td>General and Operations Manager</td><td>2986</td><td>N/A</td>
</tr>
<tr>
<td>1013</td><td>Advertising Promo Managers</td><td>3412</td><td>30%</td>
</tr>
<tr>
<td>1014</td><td>Marketing Managers</td><td>2154</td><td>5%</td>
</tr>
</tbody>
</table>
Javascript
In JavaScript we can specify a text extraction method for table sorter. While sorting higher to lower I'm trying to make the N/A as ' ' which has lower ASCII value than other symbols so the row will be in lower end of the table. Similarly lower to higher sorting i need to replace N/A with ~ symbol to give N/A a higher value to make to appear at the end.
Below is the code snippet I'm trying
$(document).ready(function () {
$("#myTable").tablesorter({
textExtraction: function (node) {
var s = '';
var hdrs = $("#myTable th");
var direction = '';
hdrs.each(function (index) {
if ($(this).hasClass('headerSortDown')) {
direction = 'down';
return;
}
else if ($(this).hasClass('headerSortUp')) {
direction = 'up';
return;
}
});
if (direction === 'down')
s = $(node).text().replace('N/A', ' ');
else if (direction === 'up')
s = $(node).text().replace('N/A', '~');
return s;
},
cssAsc: 'headerSortUp',
cssDesc: 'headerSortDown'
});
});
But it seems like the css classes are not getting added by default so the result is not as expected. My expected Result during both sort is the row while has code 1012 should always appear below the table.
Note i cant add any static classes to the table markup for the N/A values since it is from the table is generated dynamically
Thanks in advance
I'm glad that I fixed this issue by myself and I'm happy to share this to folks who might need this in future. There are two things to this issue
Tell table sorter to consider the N/A as empty. this can be done using the textExtraction(method used to extract values from the cells for sorting) method that table sorter provides
Ask tableSorter to keep all the empty values to the bottom using emptyTo attribute
Below is the code
$(document).ready(function () {
$("#myTable").tablesorter({
textExtraction: function (node) {
var txt = $(node).text();
txt = txt.replace('N/A', '');
return txt;
},
emptyTo: 'bottom'
});
});

How to make a <tr> invisible if it's <td>'s are empty?

I have a table which contains 'n' rows dynamically generated. All <td>'s may or may not contain data. I want to hide or delete '<tr>' if all it's td's are empty.
I don't know how to parse through all <td>'s and make sure it's empty or not.
example table as follows,
<table id='ex_table'>
<tr>
<td>one</td>
<td>two</td>
</tr>
<tr>
<td></td>
<td>one</td>
</tr>
<tr>
<td></td>
<td></td>
</tr>
</table>
In the above table last row need to be hidden since all it's <td>'s are empty. I prefer jquery to do this.
You don't actually have to inspect the td elements. You can select the rows and use .filter to filter out those with text content, i.e. only keep those which are empty:
$('#ex_table tr').filter(function() {
return $.trim($(this).text()) === '';
}).hide(); // or .remove()
This works because .text gets the combined inner text of all descendants and $.trim removes whitespace characters that might occur due to your HTML formatting (but are not actually content).
If you have cells which contain HTML elements but no text content (e.g. icons styled through CSS), and you want to keep those, you'd have actually have to test whether a cell contains HTML or not. The approach is basically the same as testing for text content
$('#ex_table tr').filter(function() {
return $(this).children().filter(function() {
return $.trim($(this).html()) !== '';
}).length === 0;
}).hide();
only this time we count the number of cells in a row that contain HTML. If there is none, the row is considered empty.
try something like this
$(function(){
$('#ex_table tr').each(function(){
var val = $(this).text().trim();
if(val == ''){
$(this).remove();
}
})
})
Try this:
$('#ex_table tr').each(function){
if($(this).text()==''){
$(this).remove();
}
}
Straight jQuery you say?
EDIT: I'd use Felix's answer.. just change ".hide()" to ".remove()" if you'd like to delete the element.
$('tr').each(function(){
var hasValue = false;
$(this).children().each(function(){
if ($(this).html() != "")
hasValue = true;
});
if (!hasValue)
$(this).remove();
});
Try this code
var hide;
$("tbody").find("tr").each(function(){
hide=true;
$(this).find("td").each(function(){
if($(this).html()!='') {
hide=false;
}
});
if(hide==true) {
$(this).hide();
}
});

Javascript/Jquery: Cannot target Sibling Node in Table

I have a function that hides/shows a table by clicking on it's header which is contained in a <thead> tag. When clicked the table hides and all that is left is the header, which, by clicking again, can un-hide the table.
I have multiple tables and would like to only have to use on function, instead of writing one for each table. To do this I am trying to pass the arguments (this,this.lastSibling). For some reason this.lastSibling is not targeting any object. I've tried every way of navigating the node tree I can think of, but I cannot target the tbody.
My Javascript/Jquery
function ToggleTable(trigger,target){
$(trigger).click(function(){
$(target).toggle();
ToggleTable(trigger,target)
});
}
My HTML
<table class="format2" >
<thead onmouseover="ToggleTable(this,this.lastSibling)">
<!--Title-->
</thead>
<tbody>
<!--Cells with information in here-->
</tbody>
<!--Note No TFooter Tag-->
</table>
<--Other tables similar to the one above-->
Thanks in advance!
I have a function that hides/shows a table by clicking on it's header which is contained in a <thead> tag. When clicked the table hides and all that is left is the header, which, by clicking again, can un-hide the table.
I'm lost in your current code. But If you want to toggle the visibility of the tbody (or the last child element in your <table> tag you could try this.
function ready() {
$('table > thead')
.each(function(e){
$(this).siblings(':last').hide();
})
.click(function(e) {
$(this).siblings(':last').toggle();
});
}
$(ready);
Live sample: http://bl.ocks.org/3078240
If you would like to try a solution that utilizes core JavaScript instead of jQuery shims, this might work for you. It's a function I quickly wrote that returns the last sibling that is an HTML element (e.g. not a text node) although you should be able to easily modify it to accept any node in the DOM:
function getLastSibling(el) {
var siblings, x, sib;
siblings = el.parentNode.children;
x = siblings.length;
while ((sib = siblings[x - 1]) && x >= 0) {
console.log(sib);
console.log(sib.nodeType);
if (sib.nodeType != 1 || sib.tagName == 'SCRIPT') {
x--;
} else {
return sib;
}
}
return null;
}
Assuming all your tables will have the class format2 .
Try this:
$("table.format2 > thead").click(function(){
$(this).next("tbody").toggle();
});
JSFiddle: http://jsfiddle.net/KcY4X/

JS (jQuery): Randomly trigger-click 2 table rows

Given this HTML:
<div id="TABLE1" class="tabs">
<table>
<tbody datasrc="Music">
<tr id="randomid">lorem</tr>
<tr id="foo">lorem</tr>
<tr id="abcde">lorem</tr>
<tr id="fghijk">lorem</tr>
<tr id="lmnop">lorem</tr>
<tr id="qwerty">lorem</tr>
</tbody>
</table>
</div>
<div id="TABLE_2" class="tabs">
<table>
<tbody datasrc="Music">
<tr id="random5">lorem</tr>
<tr id="farhaf">lorem</tr>
<tr id="haerf">lorem</tr>
<tr id="hagasdg">lorem</tr>
<tr id="hrfafh">lorem</tr>
<tr id="qwerty">lorem</tr>
</tbody>
</table>
</div>
<div id="LASTTABLE" class="tabs">
<table>
<tbody datasrc="Music">
<tr id="rtefdgag">lorem</tr>
<tr id="wrtjfd">lorem</tr>
<tr id="reaht">lorem</tr>
<tr id="aggag">lorem</tr>
<tr id="rthhre">lorem</tr>
<tr id="argarg">lorem</tr>
</tbody>
</table>
</div>
I am trying to trigger 2 <tr>'s from each table randomly. I cant even thing of the way doing this.
Currently for my test I use:
$("#button").on('click', function () {
$('#randomid').trigger('click')
})
but this trigger's only the first row from the first table.
So how can I:
When I press #button,
Get 2 random row's from each table, Trigger
click each row every 10 ms (so they have an order).
About the app:
It is a music player website. Each table has different style of music. Rock, Alternative, Jazz etc. There is a button 'randomly select music'). That button, will trigger 2 random tr's from each table so you end up with 2 jazz songs, 2 rock songs etc to be added to the playlist. The table looks something like this: http://dribbble.com/system/users/31916/screenshots/167289/k-dribble.png?1309036379 but those checkboxes are not actual checkboxes but images which change position on click to look and feel better than a checkbox and still act the same as a checkbox.
The user can trigger the 'checkbox' or choose a song by clicking anywhere on the row (logical), so the back-end is developed in a way to capture clicks anywhere on a row and not specificly the checkbox (thus I am not choosing to trigger those). I dont think there is a better solution that just trigger click randomly 2 row from each tble.
Support for IE8+.
See my version below,
DEMO
Note: Below code has some demo code and redundant vars which you can clean up, but I am leaving it there as to make the code look clear and self explanatory.
$(function() {
var $tables = $('table'); //gets the tree tables
var mQ = []; //music queue
var timer = null;
$('button').click(function () {
$('#result').html(''); //demo code
var t = 0, $tr;
var t1 = [];
$tables.each(function () {
$tr = $(this).find('tr');
t1[0] = Math.floor(Math.random()*$tr.length);
t1[1] = Math.floor(Math.random()*$tr.length);
while (t1[0] == t1[1]) { //To make sure not same row is selected
t1[1] = Math.floor(Math.random()*$tr.length);
}
mQ.push($tr.get(t1[0]));
mQ.push($tr.get(t1[1]));
});
timer = setInterval(function () {//Create timer to trigger click every 10ms
if (mQ.length == 0) {
clearInterval(timer);
return false;
}
$(mQ.shift()).click().addClass('selected');
}, 10);
});
$('tr').click(function () {
//do your magic
$('#result').append(this.id + '<br />');
});
});
I would first suggest that you do this a different way, but if you're set on triggering the click events here's the general idea.
$(".tab").each(function(){
var count = $(this).children(tr).length;
var r1 = Math.floor(Math.random()*count); //Get a random number less than the total count of rows
$(this).children('tr').eq(r1).trigger('click');//retrieve the nth (r1) item in the list and fire it's trigger event
});
Updated with new code on Fiddle too
Maybe more like this? ...
$(function() {
$("button").click(function(e) {
$(".selected").removeClass("selected");
$("table").each(function(i) {
var irand = {
a: Math.floor((Math.random()*($(this).find("tr").length)-1)+1),
b: undefined
};
while (irand.b == irand.a || irand.b == undefined) {
irand.b = Math.floor((Math.random()*($(this).find("tr").length)-1)+1);
};
console.log($(this).find("tr").filter(function(i) { return i == irand.a || i == irand.b }).addClass("selected"));
});
});
});​
See working fiddle here ...

Categories

Resources