470,631 Members | 1,621 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 470,631 developers. It's quick & easy.

Swapping table columns

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[i];
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

Nov 1 '05 #1
10 12277


VA wrote:
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[i];
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.

--

Martin Honnen
http://JavaScript.FAQTs.com/
Nov 1 '05 #2
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

Nov 1 '05 #3

VA wrote:
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.

--

Martin Honnen
http://JavaScript.FAQTs.com/
Nov 1 '05 #4
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[i];
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>

Nov 1 '05 #5
VA wrote:
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[i];
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[i];
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.

[...]

--
Rob
Nov 2 '05 #6
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

Nov 2 '05 #7
VA wrote:
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[i] != order1[i]){ // If one out of order
j = newIdx(order0[i], 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[i]
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'),'A BCD','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>
--
Rob
Nov 2 '05 #8
RobG wrote:
<snip>
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.
Nov 2 '05 #9
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

Nov 7 '05 #10
VA
Also, in IE, after a few iterations, IE starts to drop cells from the
last row in the table!

Nov 7 '05 #11

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

3 posts views Thread by Christopher Jeris | last post: by
61 posts views Thread by Toby Austin | last post: by
7 posts views Thread by Bing Wu | last post: by
4 posts views Thread by maricel | last post: by
1 post views Thread by kingster | last post: by
4 posts views Thread by Hemant Shah | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.