Swapping table columns

Discussion in 'Javascript' started by VA, Nov 1, 2005.

  1. VA

    VA Guest

    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
     
    VA, Nov 1, 2005
    #1
    1. Advertisements



  2. 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, Nov 1, 2005
    #2
    1. Advertisements

  3. VA

    VA Guest

    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
     
    VA, Nov 1, 2005
    #3
  4. Consider putting a sample online and posting the URL here, that way we
    can check what goes wrong.
     
    Martin Honnen, Nov 1, 2005
    #4
  5. VA

    VA Guest

    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>
     
    VA, Nov 1, 2005
    #5
  6. VA

    RobG Guest

    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;
    }


    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.

    [...]
     
    RobG, Nov 2, 2005
    #6
  7. VA

    VA Guest

    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
     
    VA, Nov 2, 2005
    #7
  8. VA

    RobG Guest

    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>
     
    RobG, Nov 2, 2005
    #8
  9. RobG wrote:
    <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.
     
    Richard Cornford, Nov 2, 2005
    #9
  10. VA

    VA Guest

    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
     
    VA, Nov 7, 2005
    #10
  11. VA

    VA Guest

    Also, in IE, after a few iterations, IE starts to drop cells from the
    last row in the table!
     
    VA, Nov 7, 2005
    #11
    1. Advertisements

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 (here). After that, you can post your question and our members will help you out.