Convert TD columns into TR rows - javascript

Is there a quick way to translate (using CSS or Javascript) a tables TD into TR, currently I have:
A B C D
1 2 3 4
and I want to translate to:
A 1
B 2
C 3
D 4
??

You want to turn HTML arranged like this:
<tr><td>A</td><td>B</td><td>C</td><td>D</td></tr>
<tr><td>1</td><td>2</td><td>3</td><td>4</td></tr>
Into this:
<tr><td>A</td><td>1</td></tr>
<tr><td>B</td><td>2</td></tr>
<tr><td>C</td><td>3</td></tr>
<tr><td>D</td><td>4</td></tr>
Correct?
You can do this with Javascript, however, it is difficult to suggest a method with out knowing more about the structure of your site/HTML files. I'll give it a go.
Assuming your <table> tag comes with an id (like this: <table id="myTable"> you can access it in javascript like this:
var myTable = document.getElementById('myTable');
You can create a new table like this:
var newTable = document.createElement('table');
Now you need to transpose the old tables rows into the new tables columns:
var maxColumns = 0;
// Find the max number of columns
for(var r = 0; r < myTable.rows.length; r++) {
if(myTable.rows[r].cells.length > maxColumns) {
maxColumns = myTable.rows[r].cells.length;
}
}
for(var c = 0; c < maxColumns; c++) {
newTable.insertRow(c);
for(var r = 0; r < myTable.rows.length; r++) {
if(myTable.rows[r].length <= c) {
newTable.rows[c].insertCell(r);
newTable.rows[c].cells[r] = '-';
}
else {
newTable.rows[c].insertCell(r);
newTable.rows[c].cells[r] = myTable.rows[r].cells[c].innerHTML;
}
}
}
This ought to do what you need. Be forewarned: not tested. Working this javascript code into an HTML page is left as an exercise for the reader. If anyone spots any errors that I missed, I be gratified if you point them out to me or simply edit to fix :)

Here is a tested function that will transpose a table, and it will preserve any formatting/events you had hooked to any elements within the table (ie: onclicks on cell or cell contents)
function TransposeTable(tableId)
{
var tbl = $('#' + tableId);
var tbody = tbl.find('tbody');
var oldWidth = tbody.find('tr:first td').length;
var oldHeight = tbody.find('tr').length;
var newWidth = oldHeight;
var newHeight = oldWidth;
var jqOldCells = tbody.find('td');
var newTbody = $("<tbody></tbody>");
for(var y=0; y<newHeight; y++)
{
var newRow = $("<tr></tr>");
for(var x=0; x<newWidth; x++)
{
newRow.append(jqOldCells.eq((oldWidth*x)+y));
}
newTbody.append(newRow);
}
tbody.replaceWith(newTbody);
}
Notes:
- Requires Jquery
- Not tested on very large tables
- Will likely crap out on tables with spanned columns/rows
- Will likely crap out on tables with any combination of thead/th
So as long as your tables have no spanned cells and doesnt use thead/th, should be good to go.

This is a solution, in this case this was for for mobiles and tablets, remove the media queries and the th position absolute and u have it!
based on this:
table, thead, tbody, th, td, tr {
display: block;
}
http://css-tricks.com/responsive-data-tables/

Maybe someone needs it: I converted TR to TD by CSS (a table with one column).
Apply from second line until end of the table on TR the code below:
<tr style="float:left;">
Also used the code below to show each 3 rows as one line of 3 columns:
<tr style="float:left; width:33.33%;">

Related

how to loop in html table and change the value of each cell in javascript

I have my input table which already filled by the user. now what I am trying to do is to loop on my table and change the value of each cell td using my JavaScript. some of my cells has input field and others only have text between td tags. I loop on my table correctly and I change the values of cells that has input field using the expression table.rows[R].cells[C].children[0].value = value; but I do not know how to change the cell that has only text between td tags without input field! tried to write table.rows[R].cells[C].value = value but its not working!
my table code:
var table = document.getElementById('table');
var rowCount = table.rows.length;
var colCount = document.getElementById('table').rows[0].cells.length;
for (var r = 1; r < rowCount; r++) {
for (var c = 1; c < colCount - 1; c++) {
table.rows[r].cells[c].children[0].value = somevalue; // this works with cells that has input field but not with cells that has not
table.rows[r].cells[c] value = somevalue; // tried this line but not working
}
}
Based on your explanation I understand that you want to modify the values of all td tags (input child or text child). In your snippet there are two problems in order to achieve this:

The start index of the “column loop” (c) is 1 and you loop until
this index is less than the length of all columns. This means that
you’ll loop through all the columns except the first and last one.
Maybe this is your intention.
You have a syntax error in the last line of the last for loop.


For your “main” problem, it seems like you are treating the cells the same even though some contain input elements and some text nodes. You can simply solve this by adding some logic and depending on if the cell has children (an input field) or not (text-node) you treat it respectively. For text nodes we simply modify the innerHTML.
Here's a snippet which should do the job for you if I understood you correctly:
var table = document.getElementById("table");
var rowCount = table.rows.length;
var colCount = document.getElementById("table").rows[0].cells.length;
var somevalue = "modified value";
for (var r = 1; r < rowCount; r++) {
for (var c = 0; c < colCount; c++) {
const cell = table.rows[r].cells[c];
if (cell.children.length) {
cell.children[0].value = somevalue;
} else {
cell.innerHTML = somevalue;
}
}
}

Move columns of a HTML table

I want to move columns of a table around in several hundred webpages that are outside of my control so that they print nicely. I can get to the tables in question easily enough with XPATH, but rearranging them has me stumped. Essentially, I want to rearrange this:
Table:
Header1 Header2
data1 data2
To this:
Table 1:
Header1
data1
Table 2:
Header2
data2
Is this possible?
Or, a simplified view of the existing HTML:
<table><tbody>
<tr>
<th>Header1</th>
<th>Header2</th>
</tr>
<tr>
<td>data1</td>
<td>data2</td>
</tr>
</tbody></table>
It isn't strictly necessary that these become separate tables, but the data portions are just wide enough to fit on a page, so they can't be in the same row.
Thanks in advance!
Update:
I have been learning jQuery, and it looks like I could use something like this:
function jqsplit($table, chunkSize) {
var cols = $("th", $table).length;
var n = cols / chunkSize;
for (var i = 0; i <= n; i++) {
$("<br/>").appendTo("body");
var $newTable = $table.clone().appendTo("body");
for (var j = cols; j > 0; j--) {
if (j + chunkSize - 1 <= chunkSize * i || j > chunkSize * i + 1) {
$('td:nth-child(' + j + '),th:nth-child(' + j + ')', $newTable).remove();
}
}
}
}
(Stolen from here, but modified for my particular use case.)
The problem I now have is that I can't figure out how to select my initial table with jquery, and if I can process them all together. The original tables always have 2 rows and 3 columns, and no other tables match that criteria, can anyone help?
OK, Solved it. My solution is inelegant as all hell, but works perfectly. Awful code, away!
function jqsplit($table, chunkSize) {
//Splits these specific tables into 3 by creating 3 copies and deleting the unneeded rows.
var $randomP = $("<p></p>").insertAfter($table);
var $newTable1 = $table.clone().appendTo($randomP);
var $newTable2 = $table.clone().appendTo($randomP);
var $newTable3 = $table.clone().appendTo($randomP);
$newTable1.children("tbody").children("tr").children("th").get(2).remove();
$newTable1.children("tbody").children("tr").children("td").get(2).remove();
$newTable1.children("tbody").children("tr").children("th").get(1).remove();
$newTable1.children("tbody").children("tr").children("td").get(1).remove();
$newTable2.children("tbody").children("tr").children("th").get(2).remove();
$newTable2.children("tbody").children("tr").children("td").get(2).remove();
$newTable2.children("tbody").children("tr").children("th").get(0).remove();
$newTable2.children("tbody").children("tr").children("td").get(0).remove();
$newTable3.children("tbody").children("tr").children("th").get(1).remove();
$newTable3.children("tbody").children("tr").children("td").get(1).remove();
$newTable3.children("tbody").children("tr").children("th").get(0).remove();
$newTable3.children("tbody").children("tr").children("td").get(0).remove();
$table.remove();
}
//Split table
var tablelist = $("table");
$.each(tablelist, function(index,value){
if ( $(this).children("tbody").children("tr").children("th").length == 3 && $(this).children("tbody").children("tr").length == 2 && $(this).children("tbody").children("tr").children("td").length == 3) {
jqsplit($(this), 1);
//Don't want to do the below because some pages have several matching tables
//return false;
}
});

Create table from Array of Strings so that each string is its own column and each row is a letter of the string

I don't know the proper way to ask this, as I have searched and tried to implement different approaches without luck. Javascript isn't my strong suit so bear with me.
I have an input that looks like, each entry can be of varied width:
#abcde#fghij#klmno
I split the input based on the characters and end up with an array that looks like:
["abcde","fghij","klmno"]
I need to output a table such that the first column contains all letters from the first string which each letter in its own row, essentially ending up with a table that looks like:
a f k
b g l
c h m
d i n
e j o
As of right now I have split the strings effectively, but am having trouble creating the table. I've tried multiple different solutions on SO without luck. My inexperience is messing me up in handling the processing at each step. I've added comments for what I think needs to go in each block of my for loop, though the implementations I have tried are not successful.
var table = document.createElement("table");
var tr = document.createElement("tr");
var td = document.createElement("td");
var th = document.createElement("th");
var checkbox = document.createElement("input");
checkbox.type("checkbox");
//split string
var splitStringArray = inputString.split("#");
for (var i = 0; i < splitStringArray; i++) {
//iterate through array and create a column for each string in the array
tr.appendChild(document.createElement(th));
//for each string, iterate through each character
var temp = splitStringArray[i].split("");
for (var j = 0; j < temp.length; j++) {
//add a row for each character in the string, each cell should have a checkbox and the letter associated with it
td.appendChild(document.createTextNode[i][j]);
td.appendChild(checkbox);
//This this the step that I'm running into issues with
}
}
tableArea.appendChild(table);
One of the problem areas I'm running into is that the strings are not going to be identical length and need to displayed in the same order than they come in.
That makes it difficult to create a set number of rows and then populate them row by row instead of column by column.
First, we split the input string on the hash character (#). Next, we filter the resultant array, returning only the elements which aren't an empty string.
From there, we create another array with the length of each of the strings in our first array. We sort this length array in descending order and take the first element - this corresponds to the length of the longest word - this will be the number of rows we need. The number of columns comes from the length of the array we calculated first - the number of words in the initial input string.
From there, we simply step through the data and create table, tr and td elements. Ideally, we should also be creating a tbody element and placing the tr elements in it instead of the table.
function newEl(tag){return document.createElement(tag)}
window.addEventListener('load', onDocLoaded, false);
function onDocLoaded(evt)
{
var tbl = testFunc('#abcde#fghij#klmno');
document.body.appendChild(tbl);
}
function testFunc(inputStr)
{
var wordArray = inputStr.split('#').filter(function(str){return str != '';});
var lengthArray = wordArray.map( function(str) {return str.length;} );
var numColumns = wordArray.length;
lengthArray.sort( function(a, b){return b-a} );
var maxRows = lengthArray[0];
var tbl = newEl('table');
var tbody = newEl('tbody');
tbl.appendChild(tbody);
for (var row=0; row<maxRows; row++)
{
var tr = newEl('tr');
for (var col=0; col<numColumns; col++)
{
var td = newEl('td');
td.textContent = wordArray[col][row];
tr.appendChild(td);
}
tbody.appendChild(tr);
}
return tbl;
}
It would look something like this:
//<![CDATA
var pre = onload, doc, bod, htm, C, E, weirdTable;
onload = function(){
if(pre)pre();
doc = document; bod = doc.body; htm = doc.documentElement;
C = function(e){
return doc.createElement(e);
}
E = function(id){
return doc.getElementById(id);
}
weirdTable = function(inputString, appendTo){
var a = inputString.split(/#/), t = C('table'), b = C('tbody');
for(var i=0,l=a.length; i<l; i++){
var r = C('tr'), s = a[i].split('');
for(var n=0,c,q=s.length; n<q; n++){
c = C('td'); c.innerHTML = s[n]; r.appendChild(c);
}
b.appendChild(r);
}
t.appendChild(b); appendTo.appendChild(t);
}
weirdTable(yourStringHere, E('yourIdHere'));
}
//]]>

Creating html table with millions record using javascript blocking browser

Please read my question complete before answer or marking it duplicate because i am dealing with constraint in my problem.
Hi All Javascript rock stars,
I am creating a html table with javascript. In table i need scroller both vertical and horizontal. I am done with this part. It is working. Now my problem starts. When i am creating millions rows for the table it block my browser. For few thousand record it work fine.
I have done lot of google to improve performance but did not gain any significant performance improvement. Like some has suggested to use row.appendChild(cell); I have also tried to use Workers. But then i found i can not have access of document object in Workers. setTimeout is also not sufficient to solve my problem. Here is my code for creating rows of table.
var arr = JSON.parse(rcvReq.responseText);
var json = arr.abc;
var columns = [];
columns = Object.keys(json[0]);
//Build an array containing Customer records.
var customers = new Array();
customers.push(columns);
for (i = 0; i < json.length; i++) {
var dataVal = [];
for(j = 0; j < columns.length; j++){
var mytempvar = json[i];
dataVal.push(mytempvar[columns[j]+'']);
}
customers.push(dataVal);
}
//Create a HTML Table element.
var table = document.createElement("TABLE");
var table1 = document.createElement("TABLE");
table.border = "1";
//Get the count of columns.
var columnCount = customers[0].length;
//Add the header row.
var row = document.createElement('tr');
row.className = 'fixed-header';
for (var i = 0; i < columnCount; i++) {
var headerCell = document.createElement("TH");
headerCell.innerHTML = customers[0][i];
row.appendChild(headerCell);
}
table1.appendChild(row);
//Add the data rows.
var documentFragment = document.createDocumentFragment();
for (var i = 1; i < customers.length; i++) {
row = document.createElement('tr');
for (var j = 0; j < columnCount; j++) {
var cellVal = customers[i][j];
var cell = document.createElement("TD");
cell.innerHTML = cellVal;
row.appendChild(cell);
}
setTimeout(function(){ }, 1000);
documentFragment.appendChild(row);
}
/* Event of button */
var siblings = e.parentNode.children;
var childOf1stShibling = siblings[0];
table.appendChild(documentFragment);
var div = document.createElement("DIV");
var dvTable = document.getElementById(siblings[1].id +'');
var dvTable1 = document.getElementById(childOf1stShibling.children[0].id + '');
dvTable.innerHTML = "";
dvTable1.innerHTML = "";
dvTable.appendChild(table);
dvTable1.appendChild(table1);
Constraint
No use of jquery. Only i can use javascript, css and html.
No use of third party plugin.
I can not use pagination.
Records are in millions not in thousand.
Please suggest any workaround keeping above constraint in mind.
Thanks so much in advance.
You can check the source of this JavaScript plugin and take the pieces you need. The whole plugin is about 300 rows of code, you can remove some parts if you do not need them. This is a link to their GitHub repo.
On their demo site they append 500k rows and the scroll is smooth.
You can not display that many DOM elements without "blocking" browser.
And there are no "optimization" techniques to handle this, the only option, as mentioned #dandavis would be to listen for scroll events and display subsets on-demand for current scroll position.
As said #Veselin Clusterize.js does exactly that, but it works vertically only. If you need to apply this technique for two directions (horizontally + vertically) - take a look at library called Fattable. Demo

Summing a table column with javascript

I'm trying to use JS to sum up a column of already Javascript-generated values. I'm new to JS, so this may be way wrong. At any rate, I tried this:
NOTE -- FINAL CODE AT BOTTOM
$(".js-package").change(function(){
var parentTable = $(this).parents("table");
var table_rows = parentTable.rows;
var height = table_rows.length;
var total = 0;
for (var i = 0; i < height; i++) {
var current_row = table_rows[i];
total += current_row[5];
}
$(parentTable).find(".js-lb-total").html((total).toFixed(2));
});
This applies to a bunch of html, but the relevant stuff is that I've got this line where things are supposed to total up:
<td class="js-lb-total">?</td>
And this further up:
<td>
<%= l.select :units, dropdown, {}, :class => "unit_select js-package" %>
</td>
Importantly, the seemingly arbitrary number 5 refers to the column (assuming JS starts arrays at 0) that I'm trying to sum up.
Any idea what I'm doing wrong/how to fix it? I'll go ahead and look into opening a fiddle that I can link to with the more complete code. I'll add that link below.
Thanks!
EDIT -- Row totaling script below
$(".js-package").change(function(){
var numOfPackages = parseFloat($(this).val());
var parentTr = $(this).parents("tr");
var parentTable = $(this).parents("table");
var weight = parseFloat($(parentTr).find(".js-weight").attr('data-weight'));
var price = parseFloat($(parentTr).find(".js-lb-price").attr('data-lb-price'));
$(parentTr).find(".js-price").html(((numOfPackages * weight * price).toFixed(2)));
$(parentTr).find(".js-lbs").html((numOfPackages * weight).toFixed(2));
});
EDIT 2 -- Basic fiddle link here Fiddle. None of the JS is working there, though, for some reason. (The first bunch works on my server). So it may not be particularly helpful.
EDIT 3 -- To be clear, I'm trying to sum a column whose values are all dynamically generated by another javascript action. They're not in the html. Could that be part of the problem?
FINAL EDIT -- After much tweaking and following of advice, I got this, which works great (and totals both price and poundage, after totaling each line).
$(".js-package").change(function(){
var numOfPackages = parseFloat($(this).val());
var parentTr = $(this).parents("tr");
var parentTable = $(this).parents("table");
var weight = parseFloat($(parentTr).find(".js-weight").attr('data-weight'));
var price = parseFloat($(parentTr).find(".js-lb-price").attr('data-lb-price'));
$(parentTr).find(".js-price").html(((numOfPackages * weight * price).toFixed(2)));
$(parentTr).find(".js-lbs").html((numOfPackages * weight).toFixed(2));
var table = document.getElementById('sumtable');
var table_rows = table.rows;
var height = parseInt(table_rows.length);
var lb_total = 0;
var money_total = 0;
var cell;
for (var i = 1, iLen = height - 1; i < iLen; i++) {
cell = table_rows[i].cells[5];
lb_total += Number(cell.textContent);
}
for (var j = 1, jLen = height - 1; j < jLen; j++) {
cell = table_rows[j].cells[6];
money_total += Number(cell.textContent);
}
$(parentTable).find(".js-lb-total").html(lb_total.toFixed(2));
$(parentTable).find(".js-price-total").html(money_total.toFixed(2));
});
The example below might get you started. If the headers and footers are in a different table section, it will make life easier, I've put them all in the one tbody.
Things to note:
Values read from cells will be strings, so you need to convert them to numbers
Javascript is notoriously bad at decimal arithmetic, much better to do integer arithmetic and convert to decimal only at the very end for presentation
Be careful of Math.toFixed, it has quirks, search the questions
Good luck. :-)
<script>
// column is the column with values in it to total (first column is zero)
// Assume values are floats.
function addRows(tableId, column, resultId) {
var table = document.getElementById(tableId);
var rows = table.rows;
var total = 0;
var cell;
// Assume first row is headers, adjust as required
// Assume last row is footer, addjust as required
for (var i=1, iLen=rows.length - 1; i<iLen; i++) {
cell = rows[i].cells[column];
total += Number(cell.textContent || cell.innerText);
}
document.getElementById(resultId).innerHTML = total.toFixed(2);
}
</script>
<table id="productTable">
<tr>
<th>Item
<th>value ($)
<tr>
<td>foo
<td>23.33
<tr>
<td>bar
<td>03.04
<tr>
<td>Total
<td id="totalValue">
</table>
<button onclick="addRows('productTable', 1, 'totalValue')">Update total</button>
try this:
total = parseInt(total)+ parseInt(current_row[5].childNodes[1].value);
if that doesn't work try getting the cell of the column you want:
total =parseInt(total)+ parseInt(current_row[5].cells[try numbers here].childNodes[1].value);
hope i helped.

Categories

Resources