Re-order table columns in HTML dynamically with Javascript - javascript

I've a table in HTML looks like this:
Subjects
n1
n2
n3
subject1
10
0
0
subject2
0
5
20
<table>
<thead>
<tr>
<th class="subject">Subjects</th>
<th>n1</th>
<th>n2</th>
<th>n3</th>
</tr>
</thead>
<tbody>
<tr>
<th class="subject">subject1</th>
<td>10</td>
<td>0</td>
<td>0</td>
</tr>
<tr>
<th class="subject">subject2</th>
<td>0</td>
<td>5</td>
<td>20</td>
</tr>
</tbody>
</table>
Is there any thought or approach with javascript I could re-order columns in a specific order let order = ['n2','n1','n3']:
Subjects
n2
n1
n3
subject1
0
10
0
subject2
5
0
20

I've solved by turning the table into 2-dimensional array and sort it and turn it back into table HTML:
function tableToArray(tbl, opt_cellValueGetter) {
opt_cellValueGetter = opt_cellValueGetter || function(td) {
return td.textContent || td.innerText;
};
var twoD = [];
for (var rowCount = tbl.rows.length, rowIndex = 0; rowIndex < rowCount; rowIndex++) {
twoD.push([]);
}
for (var rowIndex = 0, tr; rowIndex < rowCount; rowIndex++) {
var tr = tbl.rows[rowIndex];
for (var colIndex = 0, colCount = tr.cells.length, offset = 0; colIndex < colCount; colIndex++) {
var td = tr.cells[colIndex],
text = opt_cellValueGetter(td, colIndex, rowIndex, tbl);
while (twoD[rowIndex].hasOwnProperty(colIndex + offset)) {
offset++;
}
for (var i = 0, colSpan = parseInt(td.colSpan, 10) || 1; i < colSpan; i++) {
for (var j = 0, rowSpan = parseInt(td.rowSpan, 10) || 1; j < rowSpan; j++) {
twoD[rowIndex + j][colIndex + offset + i] = text;
}
}
}
}
return twoD;
}
let order = ['n2', 'n1', 'n3', "Subjects"];
const sort2dArrayColumsByFirstRow = (array) => {
if (!Array.isArray(array)) return [];
const sortedFirstRow = array[0]
.map((item, i) => ({
v: item,
i: i
}))
.sort((a, b) => {
return order.indexOf(a.v) - order.indexOf(b.v);
});
return array.map((row) => row.map((_, i) => row[sortedFirstRow[i].i]));
};
function arrayToTable(columnNames, dataArray) {
var myTable = document.createElement('table');
var y = document.createElement('tr');
myTable.appendChild(y);
for (var i = 0; i < columnNames.length; i++) {
var th = document.createElement('th'),
columns = document.createTextNode(columnNames[i]);
th.appendChild(columns);
y.appendChild(th);
}
for (var i = 0; i < dataArray.length; i++) {
var row = dataArray[i];
var y2 = document.createElement('tr');
for (var j = 0; j < row.length; j++) {
myTable.appendChild(y2);
var th2 = document.createElement('td');
var date2 = document.createTextNode(row[j]);
th2.appendChild(date2);
y2.appendChild(th2);
}
}
document.querySelector('#tableEl').innerHTML = myTable.innerHTML;
}
let arr = tableToArray(document.querySelector('#tableEl'))
console.log('before:', arr)
let arrOrdered = sort2dArrayColumsByFirstRow(arr);
console.log('after:', arrOrdered);
arrayToTable(arrOrdered[0], arrOrdered.slice(1))
<table id="tableEl">
<thead>
<tr>
<th class="subject">Subjects</th>
<th>n1</th>
<th>n2</th>
<th>n3</th>
</tr>
</thead>
<tbody>
<tr>
<th class="subject">subject1</th>
<td>10</td>
<td>0</td>
<td>0</td>
</tr>
<tr>
<th class="subject">subject2</th>
<td>0</td>
<td>5</td>
<td>20</td>
</tr>
</tbody>
</table>

This is a good DOM question.
Tables are modified by the TABLE API.
https://html.spec.whatwg.org/multipage/tables.html
The TABLE element has THEAD, TFOOT, and TBODY elements. Use of these elements provides structure for your javascript. (Good job so far).
<table id="s-table">
<thead>
<tr>
<th class="subject">Subjects</th>
<th>n1</th>
<th>n2</th>
<th>n3</th>
</tr>
</thead>
<tbody>
<tr>
<th class="subject">subject1</th>
<td>10</td>
<td>0</td>
<td>0</td>
</tr>
<tr>
<th class="subject">subject2</th>
<td>0</td>
<td>5</td>
<td>20</td>
</tr>
</tbody>
</table>
Next, you'll need some javascript.
You'll also find insertBefore, and possibly before, and after Element methods handy.
https://developer.mozilla.org/en-US/docs/Web/API/Node/insertBefore
Get the TBODY element.
For each row, reorder(cell[i], cell[j]).
Let's start with
function resortTBody(tBody) {
const rows = tBody.rows;
for(let i = 0; i < tBody.rows.length; i++) {
reorderRow(rows[i]);
}
}
function reorderRow(row) {
let cells = row.cells;
row.insertBefore(cells[2], cells[1]);
}
This code has a hard-coded swap of cells. To reorder the cells to match a specific order, you'll need to modify reorderRow:
reorderRow(row, newOrder);
The TH's can be similarly reordered.
Design Notes: It's a good idea to minimize scope of identifiers. That is, put them in scope only as broad as it can be maximally justified.
If reorderRow is only needed for resortTbody, it can be restricted to private access.
let resortTBody = function(tBody) {
function resortTBodyInner(tBody) {
const rows = tBody.rows;
for(let i = 0; i < tBody.rows.length; i++) {
reorderRow(rows[i]);
}
}
function reorderRow(row) {
let cells = row.cells;
row.insertBefore(cells[2], cells[1]);
}
resortTBodyInner(tBody);
resortTBody = resortTBodyInner;
};
It might be desirable to maintain the column headers but resort their contents. That would require a subtle change to the approach.
It might be desirable to reset the table to its original state. All of that can be done.

The following one-liner will reorganize the columns in the desired order:
document.querySelectorAll("#tableEl tr").forEach(tr=>[...tr.children].forEach((_,i,a)=>tr.append(a[[0,2,1,3][i]])));
<table id="tableEl">
<thead>
<tr>
<th class="subject">Subjects</th>
<th>n1</th>
<th>n2</th>
<th>n3</th>
</tr>
</thead>
<tbody>
<tr>
<th class="subject">subject1</th>
<td>10</td>
<td>0</td>
<td>0</td>
</tr>
<tr>
<th class="subject">subject2</th>
<td>0</td>
<td>5</td>
<td>20</td>
</tr>
</tbody>
</table>

Related

Deleting Empty Rows/Nodes

I am trying to delete the empty rows in a table. I traversed to those empty rows. But I don't know how to delete that particular node. I tried to traverse to the parent node and delete, but somehow it seems to show error.
empr[e].removeChild(empr[e].rows[et]) I used this inside the for loop
function emptyrows() {
var count = 0;
var empr = document.getElementsByClassName("tide");
var emlen = document.getElementsByClassName("tide").length;
alert(emlen);
for (var e = 0; e < emlen; e++) {
var emtab = empr[e].rows.length;
for (var et = 0; et < emtab; et++) {
if (empr[e].rows[et].innerHTML == "") {
} else {
console.log("Nothing Empty");
}
}
}
}
<table>
<tbody>
<tr>
<td>1</td>
<td>Barry</td>
<td>
<table class="tide">
<tr>50</tr>
<tr>10</tr>
<tr>200</tr>
</table>
</td>
</tr>
<tr>
<td>2</td>
<td>Allen</td>
<td>
<table class="tide">
<tr>50</tr>
<tr></tr>
<tr></tr>
</table>
</td>
</tr>
<tr>
<td>3</td>
<td>Mary</td>
<td>
<table class="tide">
<tr>50</tr>
<tr>20</tr>
<tr></tr>
</table>
</td>
</tr>
</tbody>
</table>
Try the below code, however you need to correct your HTML to be semantic (include inside ). But the code below should give you the general idea on how to proceed:
function emptyrows() {
var tables = document.getElementsByClassName("tide");
for (var i = 0; i < tables.length; i++) {
for (var j = 0; j < tables[i].childNodes.length; j++) {
if (tables[i].childNodes[j].innerHTML === '') {
tables[i].removeChild(tables[i].childNodes[j]);
}
}
}
}
emptyrows();

Sort table from side menu

It might sounds weird.
I would like to know if it's possible to sort a table by clicking on the side menu link and not from the table header.
I know that we can sort, make pagination... inside the table by using some jQuery libraries.
But my request here is to sort from the side menu and not from the table header.
<table>
<thead>
<tr>
<th>blabla</th>
<th>blabla</th>
</tr>
</thead>
<tbody>
<tr>
<td>blabla</td>
<td>blabla</td>
</tr>
</tbody>
</table>
This might give u a idea on how to do it mate..
function sortColumn(c,n){
var rows = $('#mytable tbody tr').get();
rows.sort(function(a, b) {
var A = $(a).children('td').eq(n).text().toUpperCase();
var B = $(b).children('td').eq(n).text().toUpperCase();
if(A < B) {
return -1*c;
}
if(A > B) {
return 1*c;
}
return 0;
});
$.each(rows, function(index, row) {
$('#mytable').children('tbody').append(row);
});
}
var sln = 1;
$("ul li").click(function(){
sln *= -1;
var n = $("ul li").index(this);
sortColumn(sln,n);
});
Fiddle here
You can use tablesorter's sorton event:
$(document).ready(function() {
$("#mysortable").tablesorter();
$("#navigator div").click(function() {
var column = $(this).data("column") - 1;
$("#mysortable").trigger("sorton", [[[column, 0]]]);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.19.1/js/jquery.tablesorter.min.js">
</script>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jquery.tablesorter/2.19.1/css/theme.default.css"/>
<div id="navigator" style="float:left; max-width:200px;">
<div data-column="1">Sort Column One</div>
<div data-column="2">Sort Column Two</div>
<div data-column="3">Sort Column Three</div>
</div>
<table id="mysortable" class="tablesorter" style="float:right; max-width:400px;">
<thead>
<tr>
<th>Column 1</th>
<th>Column 2</th>
<th>Column 3</th>
</tr>
</thead>
<tbody>
<tr>
<td>A</td>
<td>2</td>
<td>Z</td>
</tr>
<tr>
<td>C</td>
<td>3</td>
<td>Y</td>
</tr>
<tr>
<td>B</td>
<td>1</td>
<td>X</td>
</tr>
</tbody>
</table>
here is how
function sort_rows(col_num, ascending) {
var $rows = $('#'+table_id+' tr').not( function(i,e) {
return $(e).find('th').length > 0;
} );
var sort_values = [];
var indx_values = [];
$rows.each( function (i,e) {
sort_values.push( $(e).find('td:nth-child('+col_num+')').text() );
indx_values.push(sort_values.length-1);
} );
var ordering;
if (ascending) {
ordering = function (a,b) { return a < b; };
} else {
ordering = function (a,b) { return a > b; };
}
var k = 0, val = sort_values[0];
for(var i = sort_values.length-1; i > 0; i-=1) {
for(var j = i; j >= 0; j-=1) {
if (ordering(sort_values[j], val))
val = sort_values[j];
k = j;
}
}
var temp = sort_values[j];
sort_values[j] = sort_values[i];
sort_values[i] = temp;
var temp = indx_values[j];
indx_values[j] = sort_values[i];
indx_values[i] = temp;
}
list_$rows = [];
$rows.each( function (i,e) { list_rows.push($(e).clone()); } );
$rows.remove();
for(var i = 0; i < sort_values.length; i+=1) {
$('#'+table_id).append( list_$rows[indx_values[i]] );
}
}

JavaScript/JQuery swap horizontal and vertical order of HTML table

I have a complex HTML table with horizontal and vertical headings looking like this.
The HTML code is simple:
<table>
<tr>
<th>(empty)</th>
<th>Heading 1</th>
<th>Heading 2</th>
</tr>
<tr>
<th>Heading A</th>
<td>content for 1 and A</td>
<td>content for 2 and A</td>
</tr>
<tr>
<th>Heading B</th>
<td>content for 1 and B</td>
<td>content for 2 and B</td>
</tr>
<tr>
<th>Heading C</th>
<td>content for 1 and C</td>
<td>content for 2 and C</td>
</tr>
</table>
Now, I want to give the users of my website the possibility to swap the content of the table. I.e.: change the horizontal and vertical order, so that afterwards the vertical headings are horizontal, the horizontal headings are vertical and the table cells accordingly. Sounds complicated, but you will get it by looking at the picture:
The HTML would be now:
<table>
<tr>
<th>(empty)</th>
<th>Heading A</th>
<th>Heading B</th>
<th>Heading C</th>
</tr>
<tr>
<th>Heading 1</th>
<td>content for 1 and A</td>
<td>content for 1 and B</td>
<td>content for 1 and C</td>
</tr>
<tr>
<th>Heading 2</th>
<td>content for 2 and A</td>
<td>content for 2 and B</td>
<td>content for 2 and C</td>
</tr>
</table>
Technically speaking, evey table cell (th and td) has to swap its indices: The column index should become the row index and the column index should become the rown index. But how do I do that using JavaScript and or JQuery?
I already found out how to get the row and column index:
//column
$(this).parent().children().index(this);
//row
$(this).parent().parent().children().index(this.parentNode);
But there seems no JQuery function for "set table cell position", there is just .inserAfter and honestly, I don't know how to cope with that.
Change your html like this
<table>
<tbody>
<tr>
<td>(empty)</td>
<td>Heading 1</td>
<td>Heading 2</td>
</tr>
<tr>
<td>Heading A</td>
<td>content for 1 and A</td>
<td>content for 2 and A</td>
</tr>
<tr>
<td>Heading B</td>
<td>content for 1 and B</td>
<td>content for 2 and B</td>
</tr>
<tr>
<td>Heading C</td>
<td>content for 1 and C</td>
<td>content for 2 and C</td>
</tr>
</tbody>
</table>
And call this function
function Swap(){
var t= document.getElementsByTagName('tbody')[0],
r= t.getElementsByTagName('tr'),
cols= r.length, rows= r[0].getElementsByTagName('td').length,
cell, next, tem, i= 0, tbod= document.createElement('tbody');
while(i<rows){
cell= 0;
tem= document.createElement('tr');
while(cell<cols){
next= r[cell++].getElementsByTagName('td')[0];
tem.appendChild(next);
}
tbod.appendChild(tem);
++i;
}
t.parentNode.replaceChild(tbod, t);
}
Test it here
function invertTable(table){
var $table = $(table);
var invertedTable = [];
for(var i=0 ; i < $table.find('tr:first th').length ; i++){
invertedTable.push([]);
}
$table.find('th,td').each(function(){
invertedTable[$(this).index()].push($(this).text());
})
var $newTable = $('<table></table>');
for(var i=0 ; i < invertedTable.length ; i++){
var $newTr = $('<tr></tr>');
for(var j = 0 ; j < invertedTable[i].length ; j++){
if(j == 0 || i == 0){
$newTr.append('<th>'+invertedTable[i][j]+'</th>');
}
else{
$newTr.append('<td>'+invertedTable[i][j]+'</td>');
}
}
$newTable.append($newTr);
}
$table.after($newTable)
$table.remove();
}
http://jsfiddle.net/xybmoadx/1/
Maybe you should build two tables and hide the inapropriate each time.
html :
<table>
<tr>
<th>(empty)</th>
<th>Heading 1</th>
<th>Heading 2</th>
</tr>
<tr>
<th>Heading A</th>
<td>content for 1 and A</td>
<td>content for 2 and A</td>
</tr>
<tr>
<th>Heading B</th>
<td>content for 1 and B</td>
<td>content for 2 and B</td>
</tr>
<tr>
<th>Heading C</th>
<td>content for 1 and C</td>
<td>content for 2 and C</td>
</tr>
</table>
<table style="display:none;">
<tr>
<th>(empty)</th>
<th>Heading A</th>
<th>Heading B</th>
<th>Heading C</th>
</tr>
<tr>
<th>Heading 1</th>
<td>content for 1 and A</td>
<td>content for 1 and B</td>
<td>content for 1 and C</td>
</tr>
<tr>
<th>Heading 2</th>
<td>content for 2 and A</td>
<td>content for 2 and B</td>
<td>content for 2 and C</td>
</tr>
</table>
notice the style: "display:none;" on second table.
Now all you need to do is toogle tables when ever you whant. Lets say you want to toggle on table click :
$('table').on('click', function() {
$('table').toggle();
});
This solution assums your table is static. It is a quick and easy workarround though.
Hope that helps
PS: you can test it here
function transpose(arr){
return Object.keys(arr[0]).map(function (c) { return arr.map(function (r) { return r[c]; }); });
}
function transposeTable(table){
var rows = [];
var tableString = '';
table.find('tr').each(function(i,row){
var rowArray = [];
row = $(row);
row.find('th,td').each(function(i,cell){
cell = $(cell);
rowArray.push({
value : cell.text(),
type : cell.is('th') ? 'th':'td'
})
})
rows.push(rowArray);
});
rows = transpose(rows);
rows.forEach(function(row){
tableString += '<tr>';
row.forEach(function(cell){
tableString += '<' + cell.type + '>';
tableString += cell.value;
tableString += '</' + cell.type + '>';
})
tableString += '</tr>';
});
return tableString;
}
JSfiddle
Not clean but it works .
Buid the array dynamically from javascript. That would be the easiest way to make it... as well as maintain it.
Say a multi-dimensional array [x][y] represents all you need.
[0][0] will obviously be null...
Define a table element in HTML give it an ID, say 'table'... In JavaScript then...
Defining it should be easy...
var t = new Array();
t[0] = new Array();
t[0][0] = 'Heading 1';
t[0][1] = 'Heading 2';
and so on..
On jQuery's Document Ready event, you can initialize it...
$(document).ready(function() {
for (var i = 0; i < t.length; i++) {
$('#table').append('<tr id=tr' + 0 + '></tr>');
for (var j = 0; j < t[i].length; j++) {
if (i == 0)
$('#tr' + i).append('<th>' + t[i][j] + '</th>');
else
$('#tr' + i).append('<td>' + t[i][j] + '</td>');
}
}
var t_trans = t[0].map(function(col, i) {
return t.map(function(row) {
return row[i];
});
});
});
I've used code from this answer to transpose the created array and store it in a different variable. Transposing a 2D-array in JavaScript
Now all you need to do on click of the 'Transpose Button' in HTML is delete existing markup inside the 'table', and recreate it using the transposed array.. so during the onclick event,
$('#table').empty();
for (var i = 0; i < t_trans.length; i++) {
$('#table').append('<tr id=tr' + 0 + '></tr>');
for (var j = 0; j < t_trans[i].length; j++) {
if (i == 0)
$('#tr' + i).append('<th>' + t_trans[i][j] + '</th>');
else
$('#tr' + i).append('<td>' + t_trans[i][j] + '</td>');
}
}
This should do it... Hell, you can even make a composite function taking the array as an argument to do the job for you, something like function populate(arr){} and the nested loop inside..
function populate(arr){
for (var i = 0; i < arr.length; i++) {
$('#table').append('<tr id=tr' + 0 + '></tr>');
for (var j = 0; j < arr[i].length; j++) {
if (i == 0)
$('#tr' + i).append('<th>' + arr[i][j] + '</th>');
else
$('#tr' + i).append('<td>' + arr[i][j] + '</td>');
}
}
}
and call populate(t) on ready, populate(t_trans) after emptying it on button-click.
Look at this jsfiddle I created for you:
http://jsfiddle.net/carloscalla/yuhx2tgk/3/
It stores the table cell's values in arrays and builds up a table from them. Then swaps the order when button is clicked.
HTML:
<div id="table-wrapper"></div>
<button id="toggler">Toggler</button>
JS:
var max_rows = 4;
var a = new Array();
for (i = 0; i < max_rows; i++)
a[i] = new Array();
a[0][0] = "(empty)";
a[0][1] = "Heading 1";
a[0][2] = "Heading 2";
a[1][0] = "Heading A";
a[1][1] = "content 1 A";
a[1][2] = "content 2 A";
a[2][0] = "Heading B";
a[2][1] = "content 1 B";
a[2][2] = "content 2 B";
a[3][0] = "Heading C";
a[3][1] = "content 1 C";
a[3][2] = "content 2 C";
var direction = 0;
// 0 for horizontal
// 1 for vertical
function changeDirection(){
if (direction == 1) direction = 0;
else if (direction == 0) direction = 1;
resetTable();
}
function resetTable(){
var $table_body = $('<table><tbody></tbody></table>');
if (direction == 0){
for (x = 0; x < a.length; x++){
$table_body.append('<tr></tr>');
$last_row = $table_body.find('tr').last();
for (v = 0; v < a[x].length; v++){
$last_row.append('<td>' + a[x][v] + '</td>');
}
}
}
else{
for (x = 0; x < a[0].length; x++){
$table_body.append('<tr></tr>');
$last_row = $table_body.find('tr').last();
for (v = 0; v < a.length; v++){
$last_row.append('<td>' + a[v][x] + '</td>');
}
}
}
$('#table-wrapper').html($table_body);
}
$('#toggler').on('click', changeDirection);
Results are these:
Original table:
Updated table:

Iterate over table cells, re-using rowspan values

I have a simple HTML table, which uses rowspans in some random columns. An example might look like
A | B |
---|---| C
D | |
---| E |---
F | | G
I'd like to iterate over the rows such that I see rows as A,B,C, D,E,C, then F,E,G.
I think I can probably cobble together something very convoluted using cell.index() to check for "missed" columns in later rows, but I'd like something a little more elegant...
without jquery:
function tableToMatrix(table) {
var M = [];
for (var i = 0; i < table.rows.length; i++) {
var tr = table.rows[i];
M[i] = [];
for (var j = 0, k = 0; j < M[0].length || k < tr.cells.length;) {
var c = (M[i-1]||[])[j];
// first check if there's a continuing cell above with rowSpan
if (c && c.parentNode.rowIndex + c.rowSpan > i) {
M[i].push(...Array.from({length: c.colSpan}, () => c))
j += c.colSpan;
} else if (tr.cells[k]) {
var td = tr.cells[k++];
M[i].push(...Array.from({length: td.colSpan}, () => td));
j += td.colSpan;
}
}
}
return M;
}
var M = tableToMatrix(document.querySelector('table'));
console.table(M.map(r => r.map(c => c.innerText)));
var pre = document.createElement('pre');
pre.innerText = M.map(row => row.map(c => c.innerText).join('\t')).join('\n');
document.body.append(pre);
td {
border: 1px solid rgba(0,0,0,.3);
}
<table>
<tr>
<td colspan=2>A</td>
<td rowspan=2>B</td>
</tr>
<tr>
<td>C</td>
<td rowspan=3>D</td>
</tr>
<tr>
<td rowspan=2>E</td>
<td rowspan=4>F</td>
</tr>
<tr></tr>
<tr>
<td rowspan=2 colspan=2>G</td>
</tr>
<tr></tr>
<tr>
<td rowspan=3 colspan=3>H</td>
</tr>
<tr></tr>
<tr></tr>
<tr>
<td colspan=3>I</td>
</tr>
</table>
Try this:
<table id="tbl">
<tr>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td colspan="2" rowspan="2">A</td>
<td rowspan="2">C</td>
</tr>
<tr>
<td rowspan="2">E</td>
</tr>
<tr>
<td>F</td>
<td>G</td>
</tr>
</table>
Script:
var finalResult = '';
var totalTds = $('#tbl TR')[0].length;
var trArray = [];
var trArrayValue = [];
var trIndex = 1;
$('#tbl TR').each(function(){
var currentTr = $(this);
var tdIndex = 1;
trArray[trIndex] = [];
trArrayValue[trIndex] = [];
var tdActuallyTraversed = 0;
var colspanCount = 1;
$('#tbl TR').first().children().each(function(){
if(trIndex > 1 && trArray[trIndex - 1][tdIndex] > 1)
{
trArray[trIndex][tdIndex] = trArray[trIndex - 1][tdIndex] - 1;
trArrayValue[trIndex][tdIndex] = trArrayValue[trIndex - 1][tdIndex];
finalResult = finalResult + trArrayValue[trIndex][tdIndex];
}
else
{
if(colspanCount <= 1)
{
colspanCount = currentTr.children().eq(tdActuallyTraversed).attr('colspan') != undefined ? currentTr.children().eq(tdActuallyTraversed).attr('colspan') : 1;
}
if(colspanCount > 1 && tdIndex > 1)
{
trArray[trIndex][tdIndex] = currentTr.children().eq(tdActuallyTraversed + colspanCount).attr('rowspan') != undefined ?currentTr.children().eq(tdActuallyTraversed + colspanCount).attr('rowspan') : 1;
trArrayValue[trIndex][tdIndex] = trArrayValue[trIndex][tdIndex - 1];
colspanCount--;
}
else
{
trArray[trIndex][tdIndex] = currentTr.children().eq(tdActuallyTraversed).attr('rowspan') != undefined ?currentTr.children().eq(tdActuallyTraversed).attr('rowspan') : 1;
trArrayValue[trIndex][tdIndex] = currentTr.children().eq(tdActuallyTraversed).html();
tdActuallyTraversed++;
}
finalResult = finalResult + trArrayValue[trIndex][tdIndex];
}
tdIndex++;
});
trIndex++;
});
alert(finalResult);
Fiddle
i am not sure about the performance, but it works well.
what I understood with your question is: You want to split the merged cell with same value and then iterate the table simply by row.
I've created a JSFiddle that will split the merged cells with the same value. Then you'll have a table that can be iterated simply by rows to get the desired output that you specified.
See it running here http://jsfiddle.net/9PZQj/3/
Here's the complete code:
<table id="tbl" border = "1">
<tr>
<td>A</td>
<td>B</td>
<td rowspan="2">C</td>
</tr>
<tr>
<td>D</td>
<td rowspan="2">E</td>
</tr>
<tr>
<td>F</td>
<td>G</td>
</tr>
</table>
<br>
<div id="test"> </div>
Here's the jquery that is used to manipulate the table's data.
var tempTable = $('#tbl').clone(true);
var tableBody = $(tempTable).children();
$(tableBody).children().each(function(index , item){
var currentRow = item;
$(currentRow).children().each(function(index1, item1){
if($(item1).attr("rowspan"))
{
// copy the cell
var item2 = $(item1).clone(true);
// Remove rowspan
$(item1).removeAttr("rowspan");
$(item2).removeAttr("rowspan");
// last item's index in next row
var indexOfLastElement = $(currentRow).next().last().index();
if(indexOfLastElement <= index1)
{
$(currentRow).next().append(item2)
}
else
{
// intermediate cell insertion at right position
$(item2).insertBefore($(currentRow).next().children().eq(index1))
}
}
});
console.log(currentRow)
});
$('#test').append(tempTable);
You can use this Gist. It supports all the requirements by W3C, even "rowspan=0" (which seems to be only supported by Firefox).

Click table row and get value of all cells

I don't know JQuery, so I'm hoping there is a way to do this in pure Javascript.
I need to click on a table row and get the value of each cell in that row. Here is the format of my table:
<table class='list'>
<tr>
<th class='tech'>OCB</th>
<th class='area'>Area</th>
<th class='name'>Name</th>
<th class='cell'>Cell #</th>
<th class='nick'>Nickname</th>
</tr>
<tr onclick="somefunction()">
<td>275</td>
<td>Layton Installation</td>
<td>Benjamin Lloyd</td>
<td>(801) 123-456</td>
<td>Ben</td>
</tr>
</table>
Is there anyway short of putting a unique ID to each cell?
There is no need to add ids or add multiple event handlers to the table. One click event is all that is needed. Also you should use thead and tbody for your tables to separate the heading from the content.
var table = document.getElementsByTagName("table")[0];
var tbody = table.getElementsByTagName("tbody")[0];
tbody.onclick = function (e) {
e = e || window.event;
var data = [];
var target = e.srcElement || e.target;
while (target && target.nodeName !== "TR") {
target = target.parentNode;
}
if (target) {
var cells = target.getElementsByTagName("td");
for (var i = 0; i < cells.length; i++) {
data.push(cells[i].innerHTML);
}
}
alert(data);
};
<table class='list'>
<thead>
<tr>
<th class='tech'>OCB</th>
<th class='area'>Area</th>
<th class='name'>Name</th>
<th class='cell'>Cell #</th>
<th class='nick'>Nickname</th>
</tr>
</thead>
<tbody>
<tr>
<td>275</td>
<td>Layton Installation</td>
<td>Benjamin Lloyd</td>
<td>(801) 123-456</td>
<td>Ben</td>
</tr>
</tbody>
</table>
Example:
http://jsfiddle.net/ZpCWD/
Check this fiddle link
HTML:
<table id="rowCtr" class='list'>
<thead>
<tr>
<th class='tech'>OCB</th>
<th class='area'>Area</th>
<th class='name'>Name</th>
<th class='cell'>Cell #</th>
<th class='nick'>Nickname</th>
</tr>
</thead>
<tbody>
<tr>
<td>275</td>
<td>Layton Installation</td>
<td>Benjamin Lloyd</td>
<td>(801) 123-456</td>
<td>Ben</td>
</tr>
</tbody>
</table>
JAVASCRIPT:
init();
function init(){
addRowHandlers('rowCtr');
}
function addRowHandlers(tableId) {
if(document.getElementById(tableId)!=null){
var table = document.getElementById(tableId);
var rows = table.getElementsByTagName('tr');
var ocb = '';
var area = '';
var name = '';
var cell = '';
var nick = '';
for ( var i = 1; i < rows.length; i++) {
rows[i].i = i;
rows[i].onclick = function() {
ocb = table.rows[this.i].cells[0].innerHTML;
area = table.rows[this.i].cells[1].innerHTML;
name = table.rows[this.i].cells[2].innerHTML;
cell = table.rows[this.i].cells[3].innerHTML;
nick = table.rows[this.i].cells[4].innerHTML;
alert('ocb: '+ocb+' area: '+area+' name: '+name+' cell: '+cell+' nick: '+nick);
};
}
}
}
var elements = document.getElementsByTagName('td');
for (var i =0; i < elements.length; i++) {
var cell_id = 'id' + i;
elements[i].setAttribute('id', cell_id);
}
Maybe put something like this in function your onclick links to from the tr?
$("tr").click(function () {
var rowItems = $(this).children('td').map(function () {
return this.innerHTML;
}).toArray();
});
This shows the row's first cell which is clicked according to dataTr.querySelectorAll("td")[0].innerText;
document.querySelector("#myTable").addEventListener("click",event => {
let dataTr = event.target.parentNode;
let dataRes = dataTr.querySelectorAll("td")[0].innerText;
console.log(dataRes);
});

Categories

Resources