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>