jQuery: How to count table columns? - javascript

Using jQuery, how would you figure out how many columns are in a table?
<script>
alert($('table').columnCount());
</script>
<table>
<tr>
<td>spans one column</td>
<td colspan="2">spans two columns</td>
<td colspan="3">spans three columns</td>
<tr>
</table>
The total number of columns in this example is 6. How could I determine this using jQuery?

Here you go:
jsFiddle
$(function() {
var colCount = 0;
$('tr:nth-child(1) td').each(function () {
if ($(this).attr('colspan')) {
colCount += +$(this).attr('colspan');
} else {
colCount++;
}
});
});

$("table").find("tr:first td").length;
I edited as I didn't realize you were counting the colspan's.
If you want to include using colspan try a loop through the td's in the first row:
var cols = $("table").find("tr:first td");
var count = 0;
for(var i = 0; i < cols.length; i++)
{
var colspan = cols.eq(i).attr("colspan");
if( colspan && colspan > 1)
{
count += colspan;
}else{
count++;
}
}

This is the cleanest in my opinion. It handles tables within tables. And is short and simple:
$("table > tbody > tr:first > td").length

In POJS (Plain Old JavaScript):
HTML:
<table id="foo">
<thead></thead>
<tbody>
<tr>
<td>1</td>
<td colspan="2">2</td>
<td colspan="3">3</td>
</tr>
</tbody>
<tfoot></tfoot>
</table>
JS:
var foo = document.getElementById("foo"), i = 0, j = 0, row, cell, numCols = 0;
//loop through HTMLTableElement.rows (includes thead, tbody, tfoot)
for(i;i<foo.rows.length;i++)
{
row = foo.rows[i];
//loop through HTMLTableRowElement.cells
for(j = 0;j<row.cells.length;j++)
{
cell = row.cells[j];
numCols += cell.colSpan;
cell = null;
}
row = null;
}
alert(numCols) //6;
HTMLTableElement.rows will collect rows from every HTMLTableSectionElement (THead, TBody, and TFoot). Each section also has its own rows HTMLCollection, so you can filter them if need be.

To be robust..I'd do something like this
alert(numCol("table") + " is the max number of cols");
function numCol(table) {
var maxColNum = 0;
var i=0;
var trs = $(table).find("tr");
for ( i=0; i<trs.length; i++ ) {
maxColNum = Math.max(maxColNum, getColForTr(trs[i]));
}
return maxColNum;
}
function getColForTr(tr) {
var tds = $(tr).find("td");
var numCols = 0;
var i=0;
for ( i=0; i<tds.length; i++ ) {
var span = $(tds[i]).attr("colspan");
if ( span )
numCols += parseInt(span);
else {
numCols++;
}
}
return numCols;
}
Just in case we have some funkiness going on between different rows.

http://jsfiddle.net/WvN9u/
Just paying attention to colspan attr

Pass in a table with something like $('foo#table') or $('table:first')
function getColumnCount(e) { //Expects jQuery table object
var c= 0;
e.find('tbody tr:first td').map(function(i,o) { c += ( $(o).attr('colspan') === undefined ? 1 : parseInt($(o).attr('colspan')) ) } );
return c;
}

To circumvent the td/th issue (and also fix a potential issue where attr('colspan') was giving me strings) I went with this:
var colspan = 0;
$('#table').find('tr:first').children().each(function(){
var cs = $(this).attr('colspan');
if(cs > 0){ colspan += Number(cs); }
else{ colspan++; }
});

/**
* Get number of columns in table.
* #param {string} table jQuery selector
* #param {boolean} [malformed=false] whether to inspect each row of malformed table;
* may take some time for large tables
* #returns {?number} number of columns in table, null if table not found.
*/
function getTableColumnsCount(table, malformed) {
malformed = malformed || false;
var $table = $(table);
if (!$table.length) {
return null;
}
var rows = $table.children('thead, tfoot, tbody').children('tr');
if (!malformed) {
// for correct tables one row is enough
rows = rows.first();
}
var maxCount = 0;
rows.each(function () {
var currentCount = 0;
$(this).children('th, td').each(function () {
currentCount += this.colSpan;
});
maxCount = Math.max(maxCount, currentCount);
});
return maxCount;
}
See in action https://jsfiddle.net/kqv7hdg5.
Takes colspan into account.
Works for nested tables.
Works for <thead>, <tfoot>, <tbody>.
Works for mix of <th> and <td>.
Works for malformed tables.
Slightly modified version for those who would like to pass jQuery object instead of selector https://jsfiddle.net/5jL5kqp5.

You have to set an ID to the header row:
<table>
<tr id="headerRow">
<td>spans one column</td>
<td colspan="2">spans two columns</td>
<td colspan="3">spans three columns</td>
</tr>
</table>
And then you can use the following function:
function getColumnCount(headerRowId) {
var columnCount = 0;
$('#' + headerRowId + ' > td').each(function() {
var colspanValue = $(this).attr('colspan');
if (colspanValue == undefined) {
columnCount++;
} else {
columnCount = columnCount + parseInt(colspanValue);
}
});
return columnCount;
}

I simplified answer of Craig M.
And modified to apply to both td and th tag.
function GetColumnCount($Table)
{
var ColCount = 0;
$Table.find("tr").eq(0).find("th,td").each(function ()
{
ColCount += $(this).attr("colspan") ? parseInt($(this).attr("colspan")) : 1;
});
return ColCount;
}

var foo = document.getElementById("price-test-table")
foo.tBodies["0"].firstElementChild.children.length
Give your table an id name
Assume your rows all have the same amount of columns and you have a table body
Use above code, which I think is the simplest on here, similar to first answer
but provides a little more detail

With jQuery and reduce it could look like this:
$.fn.tableCellCount = function() {
return $(this).find('tr:first td, tr:first th').get().reduce(function(a,b) {
return a + ($(b).attr('colspan') ? parseInt($(b).attr('colspan')) : 1);
},0)
}
$('table').tableCellCount();
Or even simpler:
$.fn.tableCellCount = function() {
return $(this).find('tr:first td, tr:first th').get().reduce(function(a,b) {
return a + (b.colSpan ? parseInt(b.colSpan) : 1);
},0)
}
$('table').tableCellCount();

This is the simple solution I have done:
In case you are using TR change TH for TR.
Using JQUERY:
<script>
$(document).ready(function() {
var number = $("table > tbody > tr:first > th").length;
for(var i=0; i <= number; i++){
$('th:nth-child('+ i +')').hide();
}
});
</script>

One Line:
$('.table-responsive tr th').children().length;

function(){
num_columns = 0;
$("table td]").each(function(){
num_columns = num_columns + ($(this).attr('colspan') == undefined ? 1 : $(this).attr('colspan'));
});
return num_columns;
}

Related

How do I get the column count of a table when there are cells with rowspan/colspan?

How do I get the column count of a table when there are cells with rowspan/colspan?
UPDATE: In this question I mean the classical (as far as I know) use of tables, when it's necessary to use the colspan, though it's not required by the specification (and table will look ugly but it will be valid).
I need JavaScript/jQuery to get 11 for the following table (as 11 is the maximum number of columns for this table):
<table border="1">
<thead>
<tr>
<th rowspan="3">Lorem</th>
<th rowspan="3">ipsum</th>
<th rowspan="3">dolor</th>
<th colspan="4">sit</th>
<th colspan="4">amet</th>
</tr>
<tr>
<th colspan="3">consectetur</th>
<th rowspan="2">adipisicing</th>
<th rowspan="2">elit</th>
<th rowspan="2">sed</th>
<th rowspan="2">do</th>
<th rowspan="2">eiusmod</th>
</tr>
<tr>
<th>tempor</th>
<th>incididunt</th>
<th>ut</th>
</tr>
</thead>
<tbody></tbody>
</table>
https://jsfiddle.net/toahb3a3/
My personal solution is:
$(function(){
var max = 0;
$('tr').each(function(){
var current = 0;
$(this).find('th').each(function(){
var colspan = $(this).attr('colspan');
current += Number(colspan ? colspan : 1);
});
max = Math.max(current, max);
});
console.log(max);
});
https://jsfiddle.net/mt7qhbqd/
UPDATE: To solve this problem we need the sum of th elements plus their colspan in the very first row of thead. Thanks to Andy for his code, it's really compact and it gave me the thought that I need only the first row. Also, thanks to Quentin who pointed me to the case when colspan is not necessarily used, so Andy's alogrithm won't work (but Quentin's will). Also thanks to Quentin for helping me with the title, as my English isn't good enough.
reduce over the colspan info.
var th = document.querySelectorAll('table thead tr:first-child th');
var cols = [].reduce.call(th, function (p, c) {
var colspan = c.getAttribute('colspan') || 1;
return p + +colspan;
}, 0);
DEMO
To calculate the number of columns in a table, you need to find the row with the most columns in it. To do that, you need to test each row in turn, but take into account any cells from previous rows that span into it.
This should do the trick.
// Store the cells in each row
var rows = [];
function increment_row(index, amount) {
if (rows[index]) {
rows[index] += amount;
} else {
rows[index] = amount;
}
}
// Count the cells in each row
$("tr").each(function (row_index, row_element) {
var $row = $(row_element);
$row.children().each(function (cell_index, cell_element) {
var $cell = $(cell_element);
var row_count = parseInt($cell.attr("rowspan"), 10) || 1;
var col_count = parseInt($cell.attr("colspan"), 10) || 1;
for (var i = 0; i < row_count; i++) {
increment_row(row_index + i, col_count);
}
})
});
// Find the row with the most cells
var sorted = rows.sort();
console.log(sorted[sorted.length - 1]);
To get total colspan count - Try this:
$( document ).ready(function() {
var colspan = 0;
$( "th" ).each(function( index ) {
if(typeof $(this).attr('colspan') != 'undefined') {
colspan = colspan + parseInt($(this).attr('colspan'));
}
console.log(colspan)
});
});
Hunh, The deadliest way is either use jQuery .filter or jQuery Attribute Selector
If you want this should be for all who has digits only use this:
$(function() {
// Get total no of rowspan or colspan, if attr has numbers
var NoOfColumnHasRowSpanOrColSpan = $('th').filter(function() {
// check if attr exist
var _rowspan = $(this).attr('rowspan');
var _colspan = $(this).attr('colspan');
// check if not undefined
if (typeof _rowspan !== typeof undefined && _rowspan !== false) {
// return if attr has value as number
return /[0-9]/.test(_rowspan);
}
// same as above
if (typeof _colspan !== typeof undefined && _colspan !== false) {
return /[0-9]/.test(_colspan);
}
}).length;
// get no of count th who has rowspan or colspan and digit as value
alert(NoOfColumnHasRowSpanOrColSpan);
});
If you don't mind values:
$(function() {
// Get total no of rowspan or colspan
var NoOfColumnHasRowSpanOrColSpan = $('th[rowspan],th[colspan]').length;
// get no of count th who has rowspan or colspan
alert(NoOfColumnHasRowSpanOrColSpan);
});
Run DEMO:

How to create a table using a loop?

The individual table rows are giving me a problem. I have created what I want using divs but I need to use a table instead of divs. My table has 220 cells, 10 rows, and 22 columns. Each cell has to have the value of i inside the innerHTML. Here is similar to what i want using Divs ( although the cell height and width does not have to be set ):
<!DOCTYPE html>
<html>
<head>
<style>
#container{
width:682px; height:310px;
background-color:#555; font-size:85%;
}
.cell {
width:30px; height:30px;
background-color:#333; color:#ccc;
float:left; margin-right:1px;
margin-bottom:1px;
}
</style>
</head>
<body>
<div id="container">
<script>
for( var i = 1; i <= 220; i++ ){
document.getElementById( 'container' ).innerHTML +=
'<div class="cell">' + i + '</div>'
}
</script>
</div>
</body>
</html>
http://jsfiddle.net/8r6619wL/
This is my starting attempt using a table:
<script>
for( var i = 0; i <= 10; i++ )
{
document.getElementById( 'table' ).innerHTML +=
'<tr id = "row' + i + '"><td>...</td></tr>';
}
</script>
But that code somehow dynamically creates a bunch of tbody elements. Thanks for help as I newb
You can do this with nested loops - one to add cells to each row and one to add rows to the table. JSFiddle
var table = document.createElement('table'), tr, td, row, cell;
for (row = 0; row < 10; row++) {
tr = document.createElement('tr');
for (cell = 0; cell < 22; cell++) {
td = document.createElement('td');
tr.appendChild(td);
td.innerHTML = row * 22 + cell + 1;
}
table.appendChild(tr);
}
document.getElementById('container').appendChild(table);
Alternatively, you can create an empty row of 22 cells, clone it 10 times, and then add the numbers to the cells.
var table = document.createElement('table'),
tr = document.createElement('tr'),
cells, i;
for (i = 0; i < 22; i++) { // Create an empty row
tr.appendChild(document.createElement('td'));
}
for (i = 0; i < 10; i++) { // Add 10 copies of it to the table
table.appendChild(tr.cloneNode(true));
}
cells = table.getElementsByTagName('td'); // get all of the cells
for (i = 0; i < 220; i++) { // number them
cells[i].innerHTML = i + 1;
}
document.getElementById('container').appendChild(table);
And a third option: add the cells in a single loop, making a new row every 22 cells.
var table = document.createElement('table'), tr, td, i;
for (i = 0; i < 220; i++) {
if (i % 22 == 0) { // every 22nd cell (including the first)
tr = table.appendChild(document.createElement('tr')); // add a new row
}
td = tr.appendChild(document.createElement('td'));
td.innerHTML = i + 1;
}
document.getElementById('container').appendChild(table);
Edit - how I would do this nowadays (2021)... with a helper function of some kind to build dom elements, and using map.
function make(tag, content) {
const el = document.createElement(tag);
content.forEach(c => el.appendChild(c));
return el;
}
document.getElementById("container").appendChild(make(
"table", [...Array(10).keys()].map(row => make(
"tr", [...Array(22).keys()].map(column => make(
"td", [document.createTextNode(row * 22 + column + 1)]
))
))
));
There are a lot of ways to do this, but one I've found to be helpful is to create a fragment then append everything into it. It's fast and limits DOM re-paints/re-flows from a loop.
Take a look at this jsbin example.
Here's the modified code:
function newNode(node, text, styles) {
node.innerHTML = text;
node.className = styles;
return node;
}
var fragment = document.createDocumentFragment(),
container = document.getElementById("container");
for(var i = 1; i <= 10; i++) {
var tr = document.createElement("tr");
var td = newNode(document.createElement("td"), i, "cell");
tr.appendChild(td);
fragment.appendChild(tr);
}
container.appendChild(fragment);
You can modify whatever you want inside the loop, but this should get you started.
That's because the DOM magically wraps a <tbody> element around stray table rows in your table, as it is designed to do. Fortunately, you can rewrite your loop in a way that will add all of those table rows at once, rather than one at a time.
The simplest solution to achieve this would be to store a string variable, and concatenate your rows onto that. Then, after you've concatenated your rows together into one string, you can set the innerHTML of your table element to that one string like so:
<script>
(function() {
var rows = '';
for( var i = 0; i <= 10; i++ )
{
rows += '<tr id = "row' + i + '"><td>...</td></tr>';
}
document.getElementById( 'table' ).innerHTML = rows;
}());
</script>
Here's a JSFiddle that demonstrates what I've just written. If you inspect the HTML using your browser's developer tools, you'll notice that one (and only one) tbody wraps around all of your table rows.
Also, if you're wondering, the odd-looking function which wraps around that code is simply a fancy way of keeping the variables you've created from becoming global (because they don't need to be). See this blog post for more details on how that works.
please check this out.
This is a very simple way to create a table using js and HTML
<body>
<table cellspacing="5" >
<thead>
<tr>
<td>Particulate count</td>
<td>Temperature</td>
<td>Humidity</td>
</tr>
</thead>
<tbody id="xxx">
</tbody>
</table>
<script>
for (var a=0; a < 2; a++) {
var table1 = document.getElementById('xxx');
var rowrow = document.createElement('tr');
for ( i=0; i <1; i++) {
var cell1 = document.createElement('td');
var text1 = document.createTextNode('test1'+a);
var cell2 = document.createElement('td');
var text2 = document.createTextNode('test2'+a);
var cell3 = document.createElement('td');
var text3 = document.createTextNode('test3'+a);
cell1.appendChild(text1);
rowrow.appendChild(cell1);
cell2.appendChild(text2);
rowrow.appendChild(cell2);
cell3.appendChild(text3);
rowrow.appendChild(cell3);
}
table1.appendChild(rowrow);
}
</script>
</body>
</html>

Merge equal table cells with jQuery

Simple html table with NxM values.
The aim is to merge equal cells in column with jQuery.
Note, that in one row there are no duplicates.
I got how to hide the equal cells, but is there any way to combine a cell with data with an empty cell in one?
html:
<table border="1" id="testTable">
<tr>
<td>First</td>
<td>A</td>
<td>A</td>
</tr>
<tr>
<td>First</td>
<td>A</td>
<td>B</td>
</tr>
<tr>
<td>Second</td>
<td>V</td>
<td>S</td>
</tr>
<tr>
<td>Third</td>
<td>D</td>
<td>H</td>
</tr>
<tr>
<td>Third</td>
<td>E</td>
<td>E</td>
</tr>
</table>
js:
var seenArray = {};
$('#testTable td').each(function()
{
var index = $(this).index();
var txt = $(this).text();
if (seenArray[index] === txt)
{
$(this).text(''); //I think here should be "marging"
}
else
{
seenArray[index] = txt;
}
});
jsFiddle
P.S. One more thing, the data originally is retrieved in json array, then I do .parseJSON() first and put data in table using:
for (var i = 0; i < obj.length; i++)
{
tr = $('<tr/>');
tr.append("<td>" + obj[i]['columnA'] + "</td>");
tr.append("<td>" + obj[i]['columnB'] + "</td>");
tr.append("<td>" + obj[i]['columnC'] + "</td>");
$('#testTable').append(tr);
}
UPD
alFReD NSH made a good solution for 2 cells. Here is his solution.
But, if there will be more than 2 equal cells.
If I get what you mean here, this my edited version: http://jsfiddle.net/djhU7/4/
So instead of $(this).text('') I did this:
$($this.parent().prev().children()[index]).attr('rowspan', 2);
$this.hide();
What I did, was the I set the rowspan of first cell to 2. This attribute "will indicates for how many rows the cell extends." which will make the above cell twice bigger, and I hid the cell with the duplicate information so the extra cell will go away. Note that removing the cell will ruin the index check for the next cell. This was a just a quick and dirty solution but rowspan attribute has to be used somewhere to achieve it.
Here's another version, that sets rowspan on the time when inserting the cells into the table, beside the fact that it works with 3 duplicate cells and more, it's also faster, because it avoids re-rendering of the table(though it can be optimized more, but I don't think at this moment you wanna care about it, premature optimization is the root of all evil!): http://jsfiddle.net/g7uY9/1/
for (var i = 0; i < obj.length; i++) {
tr = $('<tr/>');
addColumn(tr, 'columnA', i);
addColumn(tr, 'columnB', i);
addColumn(tr, 'columnC', i);
$('#testTable').append(tr);
}
function addColumn(tr, column, i) {
var row = obj[i],
prevRow = obj[i - 1],
td = $('<td>' + row[column] + '</td>');
if (prevRow && row[column] === prevRow[column]) {
td.hide();
} else {
var rowspan = 1;
for (var j = i; j < obj.length - 1; j++) {
if (obj[j][column] === obj[j + 1][column]) {
rowspan++;
} else {
break;
}
}
td.attr('rowspan', rowspan);
}
tr.append(td);
}
Please find the improved answer for your query with row expand/collapse. Here is my fiddle:
function MergeGridCells()
{
var dimension_cells = new Array();
var dimension_col = null;
var i = 1;
// First, scan first row of headers for the "Dimensions" column.
$("#mytable").find('th').each(function () {
if ($(this).text() == 'Id') {
dimension_col = i;
}
i++;
});
// first_instance holds the first instance of identical td
var first_instance = null;
var rowspan=1;
// iterate through rows
$("#mytable").find('tr.parent-grid-row').each(function () {
// find the td of the correct column (determined by the dimension_col set above)
var dimension_td = $(this).find('td.parent-grid-column:nth-child(' + dimension_col + ')');
if (first_instance == null) {
// must be the first row
first_instance = dimension_td;
} else if (dimension_td.text() == first_instance.text()) {
// the current td is identical to the previous
// remove the current td
dimension_td.remove();
++rowspan;
// increment the rowspan attribute of the first instance
first_instance.attr('rowspan', rowspan);
} else {
// this cell is different from the last
first_instance = dimension_td;
rowspan=1;
}
});
}
Jquery Cell Merging
Here's a runnable version of carla's answer:
function SummerizeTable(table) {
$(table).each(function() {
$(table).find('td').each(function() {
var $this = $(this);
var col = $this.index();
var html = $this.html();
var row = $(this).parent()[0].rowIndex;
var span = 1;
var cell_above = $($this.parent().prev().children()[col]);
// look for cells one above another with the same text
while (cell_above.html() === html) { // if the text is the same
span += 1; // increase the span
cell_above_old = cell_above; // store this cell
cell_above = $(cell_above.parent().prev().children()[col]); // and go to the next cell above
}
// if there are at least two columns with the same value,
// set a new span to the first and hide the other
if (span > 1) {
// console.log(span);
$(cell_above_old).attr('rowspan', span);
$this.hide();
}
});
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button onclick="SummerizeTable('#table1')">Summerize</button>
<table id="table1" border="1" cellspacing="0" >
<thead>
<tr>
<th>State</th>
<th>City</th>
<th>Street</th>
</tr>
</thead>
<tbody>
<tr>
<td>VT</td>
<td>Burlington</td>
<td>Elm</td>
</tr>
<tr>
<td>NY</td>
<td>Manhattan</td>
<td>Main</td>
</tr>
<tr>
<td>NY</td>
<td>Manhattan</td>
<td>Oak</td>
</tr>
<tr>
<td>NY</td>
<td>Albany</td>
<td>State</td>
</tr>
</tbody>
</table>
I really liked Farid first solution, but I needed to select the range of lines and which columns it would be applied, so I made a few modifications (including the possiblity of more than 2 cells merge). http://jsfiddle.net/djhU7/72/
function Merge_cells($id_table,$lin_ini,$lin_fim,$array_col=array()){
$colunas="";
for($k=0;$k<count($array_col);$k++) $colunas=$colunas . " col =='$array_col[$k]' ||";
if(count($array_col)>0) $colunas="(".substr($colunas,0,-3).") &&";
echo "<script>
$('#$id_table td').each(function()
{
var \$this = $(this);
var col = \$this.index();
var txt = \$this.text();
var row = $(this).parent()[0].rowIndex;
//define the interval of lines and columns it will look at
if((col==0 || col==1 || col==2) row>=firstRow && row<=lastRow){
span=1;
cell_above = $(\$this.parent().prev().children()[col]);
//look for cells one above another with the same text
while(cell_above.text()=== txt){ //if the text is the same
span+=1; //increase the span
cell_above_old = cell_above; //store this cell
cell_above = $(cell_above.parent().prev().children()[col]); //and go to the next cell above
}
//if there are at least two columns with the same value, set a new span to the first and hide the other
if(span>1) {
console.log(span);
$(cell_above_old).attr('rowspan',span);
\$this.hide();
}
}
});
</script>";
}
I extended carla's solution.
With two functions, we can merge horizontally or vertically
and exclude or include cells to merge.
try the working sample. https://jsfiddle.net/bn3u63pe
/*
* merge horizontally
* ex) autoMergeByCol('theTable', 2, 0, 0);
*/
function autoMergeByCol(tableId
, rowStartIndex // zero or positive
, colStart // zero or positive
, colEnd // equals to colStart or greater than colStart or negative to go to the end of cols
) {
/*
console.log('autoMergeByCol tableId=' + tableId
+ ', rowStartIndex=' + rowStartIndex
+ ', colStart=' + colStart
+ ', colEnd=' + colEnd
);
*/
var trArr = $('#' + tableId).find('tr'); // rows array
for(var rowIndex = rowStartIndex ; rowIndex < trArr.length ; rowIndex++) {
var tdArr = $(trArr[rowIndex]).find('td'); // cols array of the row
if(colEnd < 0) colEnd = tdArr.length - 1; // if colEnd is negative, process at the end of the cols;
for(var colIndex = colStart ; colIndex < tdArr.length && colIndex <= colEnd ; colIndex++) {
var span = 1;
var theCell = $(tdArr)[colIndex];
if($(theCell).attr('rowspan')) {continue;}
var cellNext = $($(theCell).parent().children()[colIndex + span]);
while(cellNext != undefined
&& $(theCell).text() == $(cellNext).text()
&& colIndex + span <= colEnd ) {
span++;
cellNext.hide();
cellNext = $($(cellNext).parent().children()[colIndex + span]);
}
if(span > 1) $(theCell).attr('colspan', span);
}
}
}
/*
* merge vertically
* ex) autoMergeByCol('theTable', 2, 0, 0);
*/
function autoMergeByRow(tableId
, rowStartIndex // zero or positive
, colStart // zero or positive
, colEnd // equals to colStart or greater than colStart or negative
) {
/*
console.log('autoMergeByRow tableId=' + tableId
+ ', rowStartIndex=' + rowStartIndex
+ ', colStart=' + colStart
+ ', colEnd=' + colEnd
);
*/
var trArr = $('#' + tableId).find('tr'); // rows array
for(var rowIndex = rowStartIndex ; rowIndex < trArr.length ; rowIndex++) {
var tdArr = $(trArr[rowIndex]).find('td'); // cols array of the row
if(colEnd < 0) colEnd = tdArr.length - 1; // if colEnd is negative, process at the end of the cols;
for(var colIndex = colStart ; colIndex < tdArr.length && colIndex <= colEnd ; colIndex++) {
var span = 1;
var theCell = $(tdArr)[colIndex];
if($(theCell).attr('colspan')) {continue;}
var cellBelow = $($(theCell).parent().next().children()[colIndex]);
while(cellBelow != undefined
&& $(theCell).text() == $(cellBelow).text()) {
span++;
cellBelow.hide();
cellBelow = $($(cellBelow).parent().next().children()[colIndex]);
}
if(span > 1) $(theCell).attr('rowspan', span);
}
}
}
$(document).ready(function () {
SummerizeTable($('#example'));
})
function SummerizeTable(table) {
$(table).each(function () {
$(table).find('td').each(function () {
var $this = $(this);
var col = $this.index();
var html = $this.html();
var row = $(this).parent()[0].rowIndex;
var span = 1;
var cell_above = $($this.parent().prev().children()[col]);
while (cell_above.html() === html) {
span += 1;
cell_above_old = cell_above;
cell_above = $(cell_above.parent().prev().children()[col]);
}
if (span > 1) {
$(cell_above_old).attr('rowspan', span);
$this.hide();
}
});
});
}
See Working Example here.

jQuery remove elements by condition

I have some tr elements in table:
<table>
<tr id="tr_level_1">...</tr>
<tr id="tr_level_2">...</tr>
<tr id="tr_level_3">...</tr>
<tr id="tr_level_4">...</tr>
<tr id="tr_level_5">...</tr>
</table>
In Javascript I have the next variable:
var levels = 3;
I want to delete all tr's where number in id is more than levels. And if levels is more than number of tr's - adding tr's after last.
Thanls a lot.
Working demo
Try this:
var levels = 3;
$("table tr:gt("+(levels-1)+")").remove();
I substract one because this expression ("gt": greater than) is 0-based index.
For the second part of your question try this:
http://www.jsfiddle.net/dactivo/fADHL/
if($("table tr").length<levels){
//the code here for less than levels
}
else
{
$("table tr:gt("+(levels-1)+")").remove();
}
I think this should complete the answer
var levels = 3;
var $trs = $("table tr");
var currentLevels = $trs.length;
if (currentLevels > levels) {
$trs.filter(":gt(" + (levels - 1) + ")").remove();
} else if (currentLevels < levels) {
var t = "";
for (i = (currentLevels + 1); i <= levels; i++) {
t += '<tr id="tr_level_' + i + '"><td>' + i + '</td></tr>';
}
$trs.parent().after(t);
}
http://jsfiddle.net/c6XWN/1/ <-- levels = 10
http://jsfiddle.net/c6XWN/2/ <-- levels = 5
http://jsfiddle.net/c6XWN/3/ <-- levels = 3
Good luck!
try this
var total = $("#table").find('tr').length;
var levels = 3;
if(levels<=total) {
for(levels=levels;levels<=total;levels++) {
$("#tr_level_"+levels).remove();
}
}
else {
$("#table").append("<tr id=\"tr_level_"+total+1+"\">..</tr>");
// this will add the element with tr_level_6 at the end
}
Maybe this:
function editTr(inVal) {
selector = new RegExp("\d")
var lastID = selector.exec($("table tr").last().attr("id"));
if (lastID > inVal) {
$("table tr").each(function () {
if (selector.exec($(this).attr("id")) > inVal) {
$(this).remove();
}
});
}
else if (lastID < inVal) {
for (x=lastID;x<=inVal;x++) {
$("table").append("<tr id=\"tr_level_"+x+"\"></tr>")
}
}
else {
return null
}
}
var levels = 5;
var lastTr = $('#ranks_percentages tr:last').attr('id');
lastTr = lastTr.split('_');
var lastLevel = lastTr[1];
if (levels < lastLevel) {
//removing
} else {
//adding
}

Adding an onclick event to a table row

I'm trying to add an onclick event to a table row through Javascript.
function addRowHandlers() {
var table = document.getElementById("tableId");
var rows = table.getElementsByTagName("tr");
for (i = 1; i < rows.length; i++) {
row = table.rows[i];
row.onclick = function(){
var cell = this.getElementsByTagName("td")[0];
var id = cell.innerHTML;
alert("id:" + id);
};
}
}
This works as expected in Firefox, but in Internet Explorer (IE8) I can't access the table cells. I believe that is somehow related to the fact that "this" in the onclick function is identified as "Window" instead of "Table" (or something like that).
If I could access the the current row I could perform a getElementById in the onclick function by I can't find a way to do that. Any suggestions?
Something like this.
function addRowHandlers() {
var table = document.getElementById("tableId");
var rows = table.getElementsByTagName("tr");
for (i = 0; i < rows.length; i++) {
var currentRow = table.rows[i];
var createClickHandler = function(row) {
return function() {
var cell = row.getElementsByTagName("td")[0];
var id = cell.innerHTML;
alert("id:" + id);
};
};
currentRow.onclick = createClickHandler(currentRow);
}
}
EDIT
Working demo.
Simple way is generating code as bellow:
<!DOCTYPE html>
<html>
<head>
<style>
table, td {
border:1px solid black;
}
</style>
</head>
<body>
<p>Click on each tr element to alert its index position in the table:</p>
<table>
<tr onclick="myFunction(this)">
<td>Click to show rowIndex</td>
</tr>
<tr onclick="myFunction(this)">
<td>Click to show rowIndex</td>
</tr>
<tr onclick="myFunction(this)">
<td>Click to show rowIndex</td>
</tr>
</table>
<script>
function myFunction(x) {
alert("Row index is: " + x.rowIndex);
}
</script>
</body>
</html>
I think for IE you will need to use the srcElement property of the Event object. if jQuery is an option for you, you may want to consider using it - as it abstracts most browser differences for you. Example jQuery:
$("#tableId tr").click(function() {
alert($(this).children("td").html());
});
Here is a compact and a bit cleaner version of the same pure Javascript (not a jQuery) solution as discussed above by #redsquare and #SolutionYogi (re: adding onclick event handlers to all HTML table rows) that works in all major Web Browsers, including the latest IE11:
function addRowHandlers() {
var rows = document.getElementById("tableId").rows;
for (i = 0; i < rows.length; i++) {
rows[i].onclick = function(){ return function(){
var id = this.cells[0].innerHTML;
alert("id:" + id);
};}(rows[i]);
}
}
window.onload = addRowHandlers();
Working DEMO
Note: in order to make it work in IE8 as well, instead of this pointer use the explicit identifier like function(myrow) as suggested by #redsquare.
Best regards,
Head stuck in jq for too long. This will work.
function addRowHandlers() {
var table = document.getElementById("tableId");
var rows = table.getElementsByTagName("tr");
for (i = 1; i < rows.length; i++) {
var row = table.rows[i];
row.onclick = function(myrow){
return function() {
var cell = myrow.getElementsByTagName("td")[0];
var id = cell.innerHTML;
alert("id:" + id);
};
}(row);
}
}
Here is how I do this. I create a table with a thead and tbody tags.
And then add a click event to the tbody element by id.
<script>
document.getElementById("mytbody").click = clickfunc;
function clickfunc(e) {
// to find what td element has the data you are looking for
var tdele = e.target.parentNode.children[x].innerHTML;
// to find the row
var trele = e.target.parentNode;
}
</script>
<table>
<thead>
<tr>
<th>Header 1</th>
<th>Header 2</th>
</tr>
</thead>
<tbody id="mytbody">
<tr><td>Data Row</td><td>1</td></tr>
<tr><td>Data Row</td><td>2</td></tr>
<tr><td>Data Row</td><td>3</td></tr>
</tbody>
</table>
I try to figure out how to get a better result with pure JS and i get something this:
DEMO: https://jsfiddle.net/f5r3emjt/1/
const tbody = document.getElementById("tbody");
let rowSelected;
tbody.onclick = (e) => {
for (let i = 0; i < e.path.length; ++i) {
if (e.path[i].tagName == "TR") {
selectRow(e.path[i]);
break;
}
}
};
function selectRow(r) {
if (rowSelected !== undefined) rowSelected.style.backgroundColor = "white";
rowSelected = r;
rowSelected.style.backgroundColor = "dodgerblue";
}
And now you can use the variable rowSelected in other function like you want or call another function after set the style
I like more this implementacion and also compatible with any browser
tbody.onclick = (e) => {
// we need to get the tr element because we always select the td element
const tr = e.srcElement.parentNode;
tr == "TR" && selectRow( tr );
};
Try changing the this.getElementsByTagName("td")[0]) line to read row.getElementsByTagName("td")[0];. That should capture the row reference in a closure, and it should work as expected.
Edit: The above is wrong, since row is a global variable -- as others have said, allocate a new variable and then use THAT in the closure.
My table is in another iframe so i modified SolutionYogi answer to work with that:
<script type="text/javascript">
window.onload = addRowHandlers;
function addRowHandlers() {
var iframe = document.getElementById('myiframe');
var innerDoc = (iframe.contentDocument) ? iframe.contentDocument : iframe.contentWindow.document;
var table = innerDoc.getElementById("mytable");
var rows = table.getElementsByTagName("tr");
for (i = 0; i < rows.length; i++) {
var currentRow = table.rows[i];
var createClickHandler =
function(row)
{
return function() {
var cell = row.getElementsByTagName("td")[0];
var id = cell.innerHTML;
alert("id:" + id);
};
}
currentRow.onclick = createClickHandler(currentRow);
}
}
</script>
I was trying to select a table row, so that it can be easily copied to the clipboard and then pasted in Excel. Below is a small adaptation of your solution.
References:
Where I took the window.prompt line from (Jarek Milewski):
The user is presented with the prompt box, where the text to be copied is already selected...
For selecting a complete table (Tim Down). Very interesting, but I was not able to adapt for a <tr> element.
<!DOCTYPE html>
<html>
<body>
<div>
<table id="tableId" border=1>
<tbody>
<tr><td>Item <b>A1</b></td><td>Item <b>B1</b></td></tr>
<tr><td>Item <b>A2</b></td><td>Item <b>B2</b></td></tr>
<tr><td>Item <b>A3</b></td><td>Item <b>B3</b></td></tr>
</tbody>
</table>
</div>
<script>
function addRowHandlers() {
var table = document.getElementById("tableId");
var rows = table.getElementsByTagName("tr");
for (i = 0; i < rows.length; i++) {
var currentRow = table.rows[i];
var createClickHandler =
function(row)
{
return function() {
var cell = row.getElementsByTagName("td")[0];
var id = cell.innerHTML;
var cell1 = row.getElementsByTagName("td")[1];
var id2 = cell1.innerHTML;
// alert(id + " - " + id2);
window.prompt("Copy to clipboard: Ctrl+C, Enter", "<table><tr><td>" + id + "</td><td>" + id2 + "</td></tr></table>")
};
};
currentRow.onclick = createClickHandler(currentRow);
}
}
window.onload = addRowHandlers();
</script>
</body>
</html>
While most answers are a copy of SolutionYogi's answer, they all miss an important check to see if 'cell' is not null which will return an error if clicking on the headers.
So, here is the answer with the check included:
function addRowHandlers() {
var table = document.getElementById("tableId");
var rows = table.getElementsByTagName("tr");
for (i = 0; i < rows.length; i++) {
var currentRow = table.rows[i];
var createClickHandler = function(row) {
return function() {
var cell = row.getElementsByTagName("td")[0];
// check if not null
if(!cell) return; // no errors!
var id = cell.innerHTML;
alert("id:" + id);
};
};
currentRow.onclick = createClickHandler(currentRow);
}
}
selectRowToInput();
function selectRowToInput(){
var table = document.getElementById("table");
var rows = table.getElementsByTagName("tr");
for (var i = 0; i < rows.length; i++)
{
var currentRow = table.rows[i];
currentRow.onclick = function() {
rows=this.rowIndex;
console.log(rows);
};
}
}

Categories

Resources