Swapping table columns

V

VA

I got the following function to swap table columns from somewhere on
the Internet

function swapColumns (table, colIndex1, colIndex2) {
if (table && table.rows && table.insertBefore && colIndex1 !=
colIndex2) {
for (var i = 0; i < table.rows.length; i++) {
var row = table.rows;
var cell1 = row.cells[colIndex1];
var cell2 = row.cells[colIndex2];
var siblingCell1 = row.cells[Number(colIndex1) + 1];
row.insertBefore(cell1, cell2);
row.insertBefore(cell2, siblingCell1);
}
}
}

where "table" is a Table object and colIndex1 and colIndex2 are
integers representing the column numbers to swap.

Problem is...it doesnt do anything. No errors in Firefox Javascript
console, but it just doesnt do a thing!

I checked a few basic things using the JS shell from squarefree.com
like rows.length, made sure it is entering the loop, etc. But the
insertBefore doesnt seem to be doing anything.

Help? Thanks
 
M

Martin Honnen

VA said:
I got the following function to swap table columns from somewhere on
the Internet

function swapColumns (table, colIndex1, colIndex2) {
if (table && table.rows && table.insertBefore && colIndex1 !=
colIndex2) {
for (var i = 0; i < table.rows.length; i++) {
var row = table.rows;
var cell1 = row.cells[colIndex1];
var cell2 = row.cells[colIndex2];
var siblingCell1 = row.cells[Number(colIndex1) + 1];
row.insertBefore(cell1, cell2);
row.insertBefore(cell2, siblingCell1);
}
}
}


Is "somewhere" FAQTs
<http://www.faqts.com/knowledge_base/view.phtml/aid/32355/fid/192>?
There is a test case included, does that really not work for you? Then
please provide a URL where the code does not work, make sure it is a
test case with a table and script but not some long page with lots of
stuff irrelevant to the code.
 
V

VA

Martin: Thanks for replying, yes that is indeed where I got the
function from, thanks for writing it.

When I save the entire HTML document to a local file, open it in
Firefox, and click on the Swap Columns button, it works fine.

But when I use it in my own code, it doesnt work.

I did make sure that I pass in a Table object and 2 valid column
indexes to your function. I also used the JS shell to do
print(mytable.rows[0].cells[0].innerHTML) for a bunch of subscripts to
make sure I was navigating the right table. It just doesnt swap the
columns!

How can I troubleshoot this?

Thanks
 
M

Martin Honnen

VA said:
But when I use it in my own code, it doesnt work.

Consider putting a sample online and posting the URL here, that way we
can check what goes wrong.
 
V

VA

Here is my stripped down example that does not work.

Thanks for any help.

<html lang="en-us">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>reorder columns</title>
</head>
<body ><form action="dummy" >
<script type="text/javascript">
function doSomething(pThis)
{
alert('About to swap columns...');
swapColumns(document.getElementById("mytable"),1,2);
}

function swapColumns (table, colIndex1, colIndex2) {
if (table && table.rows && table.insertBefore && colIndex1 !=
colIndex2) {
alert('in swapColumns, rows='+table.rows.length);
for (var i = 0; i < table.rows.length; i++) {
var row = table.rows;
var cell1 = row.cells[colIndex1];
var cell2 = row.cells[colIndex2];
var siblingCell1 = row.cells[Number(colIndex1) + 1];
row.insertBefore(cell1, cell2);
row.insertBefore(cell2, siblingCell1);
}
}
}
</script>
<input type="button" value="Swap" onClick="doSomething(this)"></td>

<table id="mytable" cellpadding="0" border="0" cellspacing="0"
summary="0">
<tr><th id="JOB">JOB</th><th id="MGR">MGR</th><th
id="ENAME">ENAME</th><th id="EMPNO">EMPNO</th></tr>
<tr><td>null</td><td>null</td><td>null</td><td>7839</td></tr>
<tr><td>MANAGER</td><td>7839</td><td>BLAKE</td><td>7698</td></tr>
<tr><td>MANAGER</td><td>7839</td><td>CLARK</td><td>7782</td>
</tr>
<tr><td>MANAGER</td><td>7839</td><td>JONES</td><td>7566</td></tr>
<tr><td>ANALYST</td><td>7566</td><td>SCOTT</td><td>7788</td></tr>
<tr><td>CLERK</td><td>null</td><td>DOE</td><td>8000</td></tr>
<tr><td>null</td><td>null</td><td>Jane Doe</td><td>9000</td></tr>
<tr><td>null</td><td>null</td><td>Batman</td><td>1234</td></tr>
<tr><td>null</td><td>null</td><td>Superman</td><td>3333</td></tr>
<tr><td>null</td><td>null</td><td>J Doe</td><td>101</td></tr>
<tr><td>SALESMAN</td><td>7698</td><td>TURNER</td><td>7844</td></tr>
<tr><td>CLERK</td><td>7788</td><td>ADAMS</td><td>7876</td></tr>
<tr><td>null</td><td>null</td><td>asdfasdfad</td><td>5678</td></tr>
<tr><td>null</td><td>null</td><td>test</td><td>1000</td></tr>
<tr><td>null</td><td>null</td><td>Nothing</td><td>7733</td></tr>
</table>
</form>
</body>
</html>
 
R

RobG

VA said:
Here is my stripped down example that does not work.

Thanks for any help.

<html lang="en-us">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>reorder columns</title>
</head>
<body ><form action="dummy" >
<script type="text/javascript">
function doSomething(pThis)
{
alert('About to swap columns...');
swapColumns(document.getElementById("mytable"),1,2);
}

function swapColumns (table, colIndex1, colIndex2) {

The logic below is dependent on colIndex1 being the lower number, so I'd
add:

if (!colIndex1 < colIndex2){
var t = colIndex1;
colIndex1 = colIndex2;
colIndex2 = t;
}
if (table && table.rows && table.insertBefore && colIndex1 !=
colIndex2) {
alert('in swapColumns, rows='+table.rows.length);
for (var i = 0; i < table.rows.length; i++) {
var row = table.rows;
var cell1 = row.cells[colIndex1];
var cell2 = row.cells[colIndex2];
var siblingCell1 = row.cells[Number(colIndex1) + 1];
row.insertBefore(cell1, cell2);


The logic here will only work if the cells to be swapped aren't
adjacent. It swaps cell1 with the cell immediately before cell2, which
(if they're adjacent) is cell1. Swap cell2 (the higher index) first:

for (var i=0, len=table.rows.length; i<len; ++i) {
var row = table.rows;
var cell1 = row.cells[colIndex1];
var cell2 = row.cells[colIndex2];
row.insertBefore(cell2, cell1);
row.insertBefore(cell1, row.cells[colIndex2]);
}

The above will work with any column indexes, adjacent or otherwise.

[...]
 
V

VA

Thanks.

One more question:

How can I extend this concept to, say, take in a list of column indexes
(or TH ids) and re-order the columns according to that order?

Thanks
 
R

RobG

VA said:
Thanks.

One more question:

How can I extend this concept to, say, take in a list of column indexes
(or TH ids) and re-order the columns according to that order?

Thanks

There was an error in my earlier script, this line:

row.insertBefore(cell1, row.cells[colIndex2]);

should be:

row.insertBefore(cell1, row.cells[colIndex2].nextSibling);

The nextSibling bit is important when swapping non-adjacent rows.


Ordering columns is a fish of a different feather.

You first must decide which columns to swap, then swap them. Here are
some general solutions (if RC is reading this, I make no apologies for
qualifying 'solution'):

1. Determine which columns need to be swapped and do that - probably
more than one swap will be required and hopefully you have an
algorithm that lets you do it in as few as possible

2. Break the table into fragments and re-construct it in the new order

3. Clone the cells of the existing table, add them to a new table in
the new order then replace the existing table with the new one

4. Inspect the new order, wherever a column is out of order, move it to
its new position.

Which one is more efficient than the other will likely depend on the
situation, I think the last is the best as a general solution (i.e. will
work in all situations and it is sufficiently fast in most).

For example, if the columns are in the order ABCD and you are given the
order ACDB, you can do two swaps or one move. To get ACBD requires one
swap or one move, and DCBA requires two swaps or 3 moves.

Fragmenting/cloning will take the same amount of time every time, those
methods may come into their own if the tables are large and the
re-ordering is extensive.

The difference in time taken for one method compared to another may be
significant and probably varies depending on the browser and internal
algorithm for each method - e.g. DOM move versus some innerHTML/text
munging method.

Will the user want re-order the columns manually (say moving individual
columns left or right)? Will they want to prescribe the new order then
press a button to 'make it so'.

Below is a script that uses keys for the old order and the new order,
e.g. for a four column table, changing ABCD to ADBC requires 2 moves.

The maximum number of moves ever required is one less that the number of
columns (I think). It only searches through the keys, so even if a large
number of columns need lots of changes, the number of moves should be
kept close to the minimum number (though likely not often *the* minimum
number) required.

I've left out feature detection etc. The use of concat, splice etc.
means JavaScript 1.2 or better is required. It needs DOM anyway, so
what the heck. Not all browsers support the cells collection properly
(e.g. Safari 1.0.3 but fixed thereafter).

There is also very little error detection or correction, you may want to
add some.



<html><head>
<title>reorder columns</title>
</head>
<body >

<script type="text/javascript">

// Re-order table
function reorderColumn(table, order0, order1)
{
// Turn order keys into arrays
order0 = order0.split('');
order1 = order1.split('');

// Check arrays are same length
if (order0.length != order1.length) return;

// Check arrays have same elements
var x = order0.concat().sort().join('');
var y = order1.concat().sort().join('');
if (x != y) return;

// Re-order the columns
var j, k = i = order0.length;
while (i--) { // Compare each key
if (order0 != order1){ // If one out of order
j = newIdx(order0, order1) // Find new spot
moveColumn(table, i, j); // Move the column
moveEl(order0, i, j); // Move the key
i = k; // Start key comparison again
}
}
}

// returns the position of element el in array ar
// Assumes el is in ar
function newIdx(el, ar)
{
var i = ar.length;
while( ar[--i] != el){}
return i;
}

// Move a column of table from start index to finish index
// Assumes there are columns at sIdx and fIdx
function moveColumn(table, sIdx, fIdx)
{
var row, cA;
var i=table.rows.length;
while (i--){
row = table.rows
var x = row.removeChild(row.cells[sIdx]);
row.insertBefore(x, row.cells[fIdx]);
}
}

// Move element in array ar from index i to index j
// Assumes array has indexes i and j
function moveEl(ar, i, j)
{
var x = ar.splice(i,1);
ar.splice(j,0,x);
return ar; // Not needed, handy for debug
}

</script>

<input type="button" value="re-order ABCD to DCBA" onClick="
reorderColumn(document.getElementById('tableA'),'ABCD','DCBA');
"><br>

<table id="tableA" cellpadding="5" border="1"
cellspacing="5">
<tr><th>HC0</th><th>HC1</th><th>HC2</th><th>HC3</th></tr>
<tr><td>R0 C0</td><td>R0 C1</td><td>R0 C2</td><td>R0 C3</td></tr>
<tr><td>R1 C0</td><td>R1 C1</td><td>R1 C2</td><td>R1 C3</td></tr>
<tr><td>R2 C0</td><td>R2 C1</td><td>R2 C2</td><td>R2 C3</td></tr>
<tr><td>R3 C0</td><td>R3 C1</td><td>R3 C2</td><td>R3 C3</td></tr>
</table>

</body>
</html>
 
R

Richard Cornford

RobG wrote:
You first must decide which columns to swap, then swap them.
Here are some general solutions (if RC is reading this, I
make no apologies for qualifying 'solution'):
<snip>

It is not qualifying 'solution', as such, that I have an issue with. To
say a solution may be best, better, worse, worst, adequate, etc, etc is
just admitting that there are usually numerous solutions to any one
problem and that some criteria may be applied to choosing between them.
The solution is not more or less of a solution for the use of that type
of qualifier. My issue is with qualifiers that modify the meaning of
'solution' and are used to hide a failure to solve behind something that
still sounds positive. Using such qualifiers is dishonest, disingenuous
and demonstrates contempt for intelligence of the people on the
receiving end. It is the sort of thing you find in marketing (where
contempt for the intelligence of others is normal (and sometime
justified)) but it can only get in the way of discussions about
programming.

Richard.
 
V

VA

Thanks a lot, it works fine in FF, but in IE, it throws an error when
fIdx is equal to the last column in the table.

Any idea why?

Thanks
 
V

VA

Also, in IE, after a few iterations, IE starts to drop cells from the
last row in the table!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,015
Latest member
AmbrosePal

Latest Threads

Top