How can I hide the column with all empty cells including the title <th> in that column, while leaving the other columns and their titles as it is. Following jquery hides the entire <th>, which is not I want. Here is a sample, where I want to hide only the entire 'Column3' including <th>. Many thanks in advance.
$('table#mytable tr').each(function() {
if ($(this).children('td:empty').length === $(this).children('td').length) {
$(this).hide();
}
});
Took a while to piece together. Thanks to nxt for some of the code.
$('#mytable th').each(function(i) {
var remove = 0;
var tds = $(this).parents('table').find('tr td:nth-child(' + (i + 1) + ')')
tds.each(function(j) { if (this.innerHTML == '') remove++; });
if (remove == ($('#mytable tr').length - 1)) {
$(this).hide();
tds.hide();
}
});
If you want to hide the column if all cells (ignoring the header) are empty, you could do something like:
$('#mytable tr th').each(function(i) {
//select all tds in this column
var tds = $(this).parents('table')
.find('tr td:nth-child(' + (i + 1) + ')');
//check if all the cells in this column are empty
if(tds.length == tds.filter(':empty').length) {
//hide header
$(this).hide();
//hide cells
tds.hide();
}
});
Sample: http://jsfiddle.net/DeQHs/
Sample 2 (adapted for jQuery > 1.7): http://jsfiddle.net/mkginfo/mhgtmc05/
None of the solutions here worked for me. This was what I used to hide empty columns with or without a text in the header:
$('table').each(function(a, tbl) {
var currentTableRows = $(tbl).find('tbody tr').length;
$(tbl).find('th').each(function(i) {
var remove = 0;
var currentTable = $(this).parents('table');
var tds = currentTable.find('tr td:nth-child(' + (i + 1) + ')');
tds.each(function(j) { if ($(this).text().trim() === '') remove++; });
if (remove == currentTableRows) {
$(this).hide();
tds.hide();
}
});
});
http://jsfiddle.net/nlovatt/JsLn8/
A multi-table example which avoids using the table id in the selectors
You need the next code:
HTML
<table id="mytable" border="1">
<thead>
<tr><th>Column1</th><th>Column2</th><th>Column3</th><th>Column4</th></tr>
</thead>
<tbody>
<tr class="data"><td>1st</td><td>1.1</td><td></td><td>1</td></tr>
<tr class="data"><td>2nd</td><td>2.01</td><td></td><td>2</td></tr>
<tr class="data"><td>3rd</td><td>3.001</td><td></td><td>3</td></tr>
<tr class="data"><td>4th</td><td>4.01</td><td></td><td>4</td></tr>
</tbody>
</table>
JavaScript
var $table = $('#mytable');
var thead = $table[0].tHead, tbody = $table[0].tBodies[0];
var colsLen = tbody.rows[0].cells.length, rowsLen = tbody.rows.length;
var hideNode = function(node) { if (node) node.style.display = "none"; };
for (var j = 0; j < colsLen; ++j) {
var counter = 0;
for (var i = 0; i < rowsLen; ++i) {
if (tbody.rows[i].cells[j].childNodes.length == 0) ++counter;
}
if (counter == rowsLen) {
for (var i = 0; i < rowsLen; ++i) {
hideNode(tbody.rows[i].cells[j]);
}
hideNode(thead.rows[0].cells[j]);
}
}
If the table data are from a MySQL query it possible to verify if a column is empty by using count on the field (count = 0 means that there are no values).
It is quite fastidious when you have many fields, and the IF condition is needed for the corresponding header and footer cells too. But it works...
if ($sum_field>'0') echo "<th>field</th>";
if ($sum_field>'0') echo "<td>" . $row['field'] . "</td>";
#nmat solution works fine but doesn't handle footers.
Related
I have a table like this link.
How can I know the td(input) I clicked is the first row or last row?
And how can I know the column index of td and the row index of td I clicked?
I know I can use $(this), but how to do?
$("#table_reach_condition_appoint tbody td").click(function(){
//$(this)
})
Here is an example how you can do it. index() returns the index of the current position of the selected element. It starts with index 0. Therefore we need to add +1 to the result to get the correct row/column number.
$(function(){
$('td').on('click', function(){
var columnNumber = $(this).index() + 1; // add 1 because index starts with 0
var rowNumber = $(this).parent('tr').index() + 1;
//Check if the culculated row number is 1
firstcolumn = (columnNumber === 1);
firstRow = (rowNumber === 1);
//Compare the clicked element with the last element using jQuery's is() function.
lastRow = $(this).parent('tr').is(':last-child');
lastColumn = $(this).is(':last-child');
console.log('clicked on: ' + $(this).text());
console.log('row: ' + rowNumber);
console.log('column: ' + columnNumber);
if(firstcolumn) {
console.log('firstColumn');
}
if(firstRow) {
console.log('firstRow');
}
if(lastRow) {
console.log('lastRow');
}
if(lastColumn) {
console.log('lastColumn');
}
})
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<tr>
<td>1A</td>
<td>2A</td>
<td>3A</td>
<td>4A</td>
</tr>
<tr>
<td>1B</td>
<td>2B</td>
<td>3B</td>
<td>4B</td>
</tr>
</table>
$("#table_reach_condition_appoint tbody td").each(function() {
$(this).on('click', function() {
var row = $(this).parent('tr').index(),
column = $(this).index();
console.log(row, column);
});
})
Row and Column will start at 0 unless otherwise specified.
$("#table_reach_condition_appoint tbody td").click(function(){
var tbl_row_count = $('#table_reach_condition_appoint>tbody>tr').length;
var col_no = parseInt($(this).index())+1;
var row_no = parseInt($(this).closest('tr').index())+1;
if(row_no == 1)
{
alert('first row');
}
if(row_no == tbl_row_count)
{
alert('last row');
}
alert('You clicked row no'+row_no+' col no'+col_no);
});
I'm creating a simple dropdown plugin where the values of the dropdown were in tabular manner.
what I want is to halt the event while my table is being loaded.
here's my code.
//appendTableForThePanel
$('#appendHere').append('<table class="table table-hover table-condensed"></table>');
$('#appendHere').find('table').append('<thead></thead>');
$('#appendHere').find('table').append('<tbody></tbody>');
$('#appendHere').find('table').find('thead').append('<tr></tr>');
for(appendCountHeader = 0; appendCountHeader < tableHeader.length; appendCountHeader++ ){
$('#appendHere').find('table').find('thead').find('tr').append('<th>'+tableHeader[appendCountHeader]+'</th>');
}
//count tbody tbody_tr
var tbody_tr = tbody.length / tableHeader.length;
//count how many column / row
var tbody_td = tbody.length / tbody_tr;
//append tbody tr tdcontent
for(var i = 0; i < tbody.length; i += tbody_td) {
$newRow = $("<tr>");
for(var j = 0; j < tbody_td; j++) {
$newRow.append(
$("<td>").html(tbody[i + j])
);
}
$("#appendHere").find('table').find('tbody').append($newRow);
}
$('body').on('click', '#appendHere table tbody tr', function() {
// alert($(this).find('td:nth-child(1)').html() + ' : ' + $(this).find('td:nth-child(2)').html());
$($element.selector).val($(this).find('td:nth-child(2)').html());
$('#appendHere').hide();
});
// **I want to deferred below functions when the table is appending**
$($element.selector).blur(function(){
setTimeout(function(){
$('#appendHere').hide();
}, 200);
});
$($element.selector).on('click', function(){
$('#appendHere').show();
});
$($element.selector).keyup(function(){
});
I know it is possible but I can't grasp the idea of deferring a function.
thanks in advance.
I'm trying to make a script to make my applications tables more mobile friendly.
The tables are all very similar, but very in number of row and columns, since they will be dynamically created, I'll have little control over this, so i've come up with the script below, it almost works but one function is not be passed on to each table, it stops after the first.
I suggest looking at the js fiddle: http://jsfiddle.net/e4vC3/1/
Here is the piece of the script that is not working correctly:
// Create content for new headers in mobile table by copying from original table
var HeaderArray = [];
$("table thead tr th").each(function(){
var innerArray = [];
$(this).each(function () {
innerArray.push($(this).text());
});
HeaderArray.push(innerArray); // Put content for new headers in array
});
$("table.mobile_table tbody tr").each(function(index, elem){ // Place content of array where array position and row index are the same
$(this).find("td").first().text(HeaderArray[index]);
});
Again, if you check the fiddle, you will see that the first arry stops copying objects after the first table, i cant get it to run all the way thought.
If anyone could help me with them, i would really, realy appreciate it..... http://jsfiddle.net/e4vC3/1/
The problem is that there are multiple data rows while only 1 header row. So, you will have to use mod operator like this(index has been replaced with index % TableSize):
$("table.mobile_table tbody tr").each(function(index, elem){ // Place content of array where array position and row index are the same
$(this).find("td").first().text(HeaderArray[index % TableSize]);
});
Updated your code # http://jsfiddle.net/souviiik/e4vC3/4/, see if this is helpful. For the first mobile_table I was not able to put the TH values, I hope you can modify my code :)
var TableSize = $("#ContactsPhoneTable .tableHedaer").size(); // Get # of columns
var i = 1;
var TableRowCount = $(".no_edit").size(); // Get # of body rows
$(".tableHedaer").each(function () {
$(this).attr("id", i++); // Give headers incrementing ID
});
for (var CreateTables = 1; CreateTables < TableRowCount; CreateTables++) { // Create new table class="mobile_table" for each row
$("table").after("<table class='mobile_table'></table>");
}
for(var i = 0 ; i < TableSize ; i++)
{
var tableRow = $("<tr/>").appendTo(".mobile_table");
for(var j = 0 ; j < TableRowCount ; j++)
{
var cellValue = $("#ContactsPhoneTable").find("tr").eq(i).find("td").eq(j).text();
$("<td/>", {
text: cellValue
}).appendTo(tableRow);
}
}
Updated code is at http://jsfiddle.net/souviiik/b6QZT/2/, see if this is acceptable. The code is as below.
var columnCount = $("table thead tr th").not("table.mobile_table thead tr th").size(); // Get # of columns
var rowCount = $("table tbody tr").size(); // Get # of body rows
for (var CreateTables = 0; CreateTables < rowCount; CreateTables++) { // Create new table class="mobile_table" for each row
$("<table/>", {
"class": "mobile_table"
}).appendTo(".newTableContainer");
}
var tableHedaers = [];
for(var th = 0 ; th < columnCount ; th++)
{
tableHedaers.push($(".sortable th").eq(th).text());
}
$(".mobile_table").each(function(idx){
var thisTable = $(this);
for(var i = 0 ; i < columnCount ; i++)
{
var thisTableRow = $("<tr/>").appendTo(thisTable);
for(var j = 0 ; j < 2 ; j++)
{
if(j == 0)
{
$("<td/>", {
"text": tableHedaers[i],
"style": "font-weight: 700"
}).appendTo(thisTableRow);
}
else
{
var cellValue = $("#ContactsPhoneTable").find("tr").eq(idx+1).find("td").eq(i).text();
$("<td/>", {
"text": cellValue
}).appendTo(thisTableRow);
}
}
}
});
I have a gridview that is being rendered as follows
<table cellspacing="0" cellpadding="4" rules="cols" id="ContentPlaceHolder1_ucstockcount1_GridView1" style="color:Black;background-color:White;border-color:#DEDFDE;border-width:1px;border-style:None;width:100%;border-collapse:collapse;">
<tr style="color:White;background-color:#6B696B;font-weight:bold;">
<th scope="col">Sr.no</th><th scope="col">Style</th><th scope="col">Stk Last Mon</th><th scope="col">Stk Received</th><th scope="col">Stk This Mon</th><th scope="col">Change</th><th scope="col">Price</th><th scope="col">Value</th>
</tr><tr style="background-color:#F7F7DE;">
<td>1</td><td>T1-34H</td><td>0</td><td>0</td><td>
<input name="ctl00$ContentPlaceHolder1$ucstockcount1$GridView1$ctl02$TextBox2" type="text" id="ContentPlaceHolder1_ucstockcount1_GridView1_TextBox2_0" onblur="updatevals("ContentPlaceHolder1_ucstockcount1_GridView1_TextBox2_0",0,0,5.00,"ContentPlaceHolder1_ucstockcount1_GridView1_Label1_0","ContentPlaceHolder1_ucstockcount1_GridView1_Label2_0")" />
</td><td>
<span id="ContentPlaceHolder1_ucstockcount1_GridView1_Label1_0">0</span>
</td><td>5.00</td><td>
<span id="ContentPlaceHolder1_ucstockcount1_GridView1_Label2_0">0</span>
</td>
</tr><tr style="background-color:White;">
<td>2</td><td>T1-43B</td><td>0</td><td>0</td><td>
<input name="ctl00$ContentPlaceHolder1$ucstockcount1$GridView1$ctl03$TextBox2" type="text" id="ContentPlaceHolder1_ucstockcount1_GridView1_TextBox2_1" onblur="updatevals("ContentPlaceHolder1_ucstockcount1_GridView1_TextBox2_1",0,0,5.00,"ContentPlaceHolder1_ucstockcount1_GridView1_Label1_1","ContentPlaceHolder1_ucstockcount1_GridView1_Label2_1")" />
</td><td>
<span id="ContentPlaceHolder1_ucstockcount1_GridView1_Label1_1">0</span>
</td><td>5.00</td><td>
<span id="ContentPlaceHolder1_ucstockcount1_GridView1_Label2_1">0</span>
</td>
</tr>
I use the following code to extract values at client side.
function updatea(grid) {
$('#' + grid + ' tr').each(function (i) {
var style = "";
var lastmon = 0;
var received = 0;
var thismon = 0;
var change = 0;
var price = 0;
var value = 0;
$(this).children('td').each(function (j) {
if (j == 2) {
style = $(this).html();
} else if (j == 3) {
lastmon = $(this).html();
} else if (j == 4) {
received = $(this).html();
} else if (j == 5) {
thismon = $(this).children('input').val().trim();
alert(thismon);
}
// else if (j == 6) {
// change = $(this).children('span').val().trim();
// alert(change);
// }
// alert($(this).html());
});
});
}
Till 4th column I am able to get values as required but when i need to extract the value of a textbox that is inside the 5th column I get error TypeError: $(...).children(...).val(...) is undefined
I have taken the code from Traverse html table using jQuery
please help. Thankx
Two problems, the index starts from 0 so column with index 4 has input element, second the first row does not have input element
function updatea(grid) {
//start processing from row 1
$('#' + grid + ' tr').slice(1).each(function (i) {
var style = "";
var lastmon = 0;
var received = 0;
var thismon = 0;
var change = 0;
var price = 0;
var value = 0;
$(this).children('td').each(function (j) {
if (j == 1) {
style = $(this).html();
} else if (j == 2) {
lastmon = $(this).html();
} else if (j == 3) {
received = $(this).html();
//column 5 has index 4
} else if (j == 4) {
thismon = $(this).children('input').val().trim();
alert(thismon);
}
});
});
}
Demo: Fiddle
The index in each() is zero based, and the fifth TD doesn't have an input, the fourth has:
} else if (j == 4) {
thismon = $(this).children('input').val().trim();
alert(thismon);
}
You can make selections easier this way
$('#' + grid + ' tr').slice(1).each(function (i) {
var style = $('td:eq(1)', this).html();
var lastmon = $('td:eq(2)', this).html();
var received = $('td:eq(3)', this).html();
var thismon = $('td:eq(4) input', this).val();
}
+1 to #arun-p-johny for .slice(1)
Sometimes val() function didn't work for me in some conditions. You may test attr('value') instead of val() or you can change children() to $($(this).find('input')).val().trim() or $(this+'input').val().trim() or $(this).children().val().trim()
So I don't really remember right now but sometimes the returning object is not DOM Object.
Finally you can test $($(this).children('input')).val().trim().
As you can see there are too much moves to find anything. I just focused the main problem, so you need to test these and if any of them don't work, just tell me.
But I think the main problem is returning value is not DOM object. So it tries to reach non object and it gives error.
I have multiple column headers that spans of multiple column and I would like to find the correct header number/count for the columns.
I want to enter a column number and get the header: example column 5 is RDataTest6 $('td.eq(5)) and its header is HTest3 $('th.eq(2))
Example:
<table>
<tr>
<th>HTest1</th>
<th colSpan="2">HTest2</th>
<th colSpan="4">HTest3</th>
<th colSpan="2">HTest4</th>
</tr>
<tr>
<td>RDataTest1</td>
<td>RDataTest2</td>
<td>RDataTest3</td>
<td>RDataTest4</td>
<td>RDataTest5</td>
<td>RDataTest6</td>
<td>RDataTest7</td>
<td>RDataTest8</td>
<td>RDataTest9</td>
</tr>
</table>
Edit: You should implement a simple array that hold the header location, see below,
var thLocator = [], colCount = 1;
$table.find('tr:first th').each(function () {
for (var i = 0; i < this.colSpan; i++) {
thLocator.push(colCount);
}
colCount++;
});
$table.find('td').click(function () {
alert(thLocator[$(this).index()]);
});
And then anytime You can get the location of a td column. See DEMO -> Click on any TD to identify its col head position.
I am not sure which count you want so I wrote down all col count. See DEMO
$(function() {
var $table = $('table');
alert('Table Header Count ' + $table.find('tr:first th').length);
var thCount = 0;
$table.find('tr:first th').each(function () {
thCount += this.colSpan;
});
alert('Computed TH Count ' + thCount );
alert('Table TD Col Count ' + $table.find('tr:eq(1) td').length);
});
That's easy, as long as you don't have any rowspans:
function getCell(tr, col) {
var cell = tr.firstElementChild;
while (cell && (col -= cell.colSpan || 1)>=0)
cell = cell.nextElementSibling;
return cell;
}
See demonstration.