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;
}
});
Related
I've been stuck on this stupid problem for a few days now. I guess it's not complicated but I might need someone's help...
Here is the thing: I start with an empty table in my html page. There is only the head with the name of the columns. Then, I get JSON data thanks to php, and I fill my table by creating a new row and new cells as follows:
for (var j = 0; j < jsonVal.length; j++){
var tr = table.insertRow(-1);
tr.insertCell(-1).innerHTML = "<img src=\"" + jsonVal[j].image + "\">";
tr.insertCell(-1).innerHTML = jsonVal[j].name;
tr.insertCell(-1).innerHTML = jsonVal[j].rating;
};
Now, all I want to do is to update this table according to some parameters (ordered by name or rating, only 5 lines etc...)
To do so, I want to delete all the rows I currently have to put with the new data. BUT I can't find a way to delete them. Here is my deleting code:
var currentTable = document.getElementsByTagName("table")[0];
var rowCount = currentTable.rows.length;
for(var i = 1; i < rowCount; i++){
currentTable.deleteRow(i);
}
I get the following error:
IndexSizeError: Index or size is negative or greater than the allowed amount
Is that the correct way to do it?
PS: sorry for such a long explanation.
My bad, I only needed to change i to 1 in my for loop as follows:
var currentTable = document.getElementsByTagName("table")[0];
var rowCount = currentTable.rows.length;
for(var i = 1; i < rowCount; i++){
currentTable.deleteRow(1);
}
I am kind of new to javascript and trying to accomplish a simple (yet complicated for me) task. I am trying to exclude first row and first column from a table and got stuck in excluding first cell in every row from this table (HTMLTableRowElement). Following is my sample code.
function clickSchedule(){
var table
var grow // group row
table= document.getElementById("myTable");
grow = table.rows;
for(var i= 1; i<= grow.length ; i++ ){
var cellIndex = this.cells;
for( var j =1 ; j<= cellIndex.length ; j++ ){
this.onclick = function () {
alert("test");
}
}
}
The first "for loop" will grab all rows from the table excluding row[0] that is why you can see var i = 1. Next, I am storing cells from all rows to a variable and trying to exclude cell[0] using second "for loop" in order to perform an onclick event to the selected table area.
Also, is it possible to get the index value of the selected cell from this table?
I would really appreciated your help
Faraz Amjad
Your logical part is right and wrong.
Start iteration from index 1 is right.
i <= grow.length means when it's true, go on iteration. But when i == grow.length, grow[i] should be undefined, because grow.length-1 is the last index. So the right condition expression should be i < grow.length.
You didn't do event binding right in iterations.
Try this one:
(function(){
var table = document.querySelector('table')
var rows = table.rows
var cells
for(var i = 1; i < rows.length; i++ ) {
cells = rows[i].cells
for(var j = 1; j < cells.length; j++ ) {
cells[j].onclick = function() {
alert(this.innerHTML);
}
}
}
})()
<table>
<tr>
<td>a1</td><td>a2</td><td>a3</td><td>a4</td>
</tr>
<tr>
<td>b1</td><td>b2</td><td>b3</td><td>b4</td>
</tr>
<tr>
<td>c1</td><td>c2</td><td>c3</td><td>c4</td>
</tr>
<tr>
<td>d1</td><td>d2</td><td>d3</td><td>d4</td>
</tr>
</table>
I am searching my Table Column for the string "None". It does this but I am unable to get the row number after. I am attempting to use the "rowIndex" attribute. Not sure why it is pulling "Not a Number" (NaN). Table is 50 rows 10 cols. I am assuming it may have to do with that I am pulling from a column instead of Row.
function F0416()
{
var tab = document.getElementById('part1Table');
var l = tab.rows.length;
var s = '';
for ( var i = 0; i < l; i++ )
{var tr = tab.rows[i];
var cll = tr.cells[2];
s += ' ' + cll.innerText;
}
var y = (s.indexOf('None') != -1)
document.write(this.rowIndex + 1)
Instead of concatenating all the values of the column into a string and searching the string, you could instead test the value of each cell in the column for the value 'None'. Then you would know the row number from the loop counter, and you could halt the loop if you find it instead of iterating over every row.
It would look more like this:
for ( var i = 0; i < l; i++ ) {
var tr = tab.rows[i];
var cll = tr.cells[2];
if(cll.innerText.indexOf('None') != -1) {
document.write(i + 1);
break;
}
}
You could also return the value of the row instead of outputting it.
I would recommend using a rich javascript library like JQuery.
Then given the following HTML:
<table>
<tr><td>Row 1- Column 1</td><td>Row 1 - Column 2</td>
<tr><td>none</td><td>Row 2 - Column 2</td>
<tr><td>Row 3- Column 1</td><td>Row 3 - Column 2</td>
</table>
You can use the following to get all the rows containing none:
var rows = $('table tr').filter(":contains('none')");
Have a look at this Fiddle example.
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.
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%;">