Drag and drop table rows with JavaScript

REDIPS.drag was initially built to drag and drop table content. After publishing first version of REDIPS.drag, I received a lot of questions about dragging table rows also. Now is possible to drag and drop table rows as well as table content. First column and contained DIV element in this demo is a row handler, so you can try to drag table rows.


REDIPS.drag example15

It is very easy to define a row handler. Actually, it is only needed to place DIV element to the column (first, last or any other) and to define class=”drag row”. This DIV element will become a row handler. When row dragging begins, source row will change color and content will become transparent. This way, source row as start point is visible and obvious. It is possible to return row to the start point – in this case, event.rowDroppedSource() will be fired. In a moment when row is dropped to the destination table, source row will be removed. How REDIPS.drag works? The trick is to clone a mini table from the source table and to remove all rows except selected row. It looks like a row, but it is a table with only one row – a mini table. New functionality also brings new event handlers:

  1. event.rowChanged
  2. event.rowClicked
  3. event.rowCloned
  4. event.rowDeleted
  5. event.rowDropped
  6. event.rowDroppedBefore
  7. event.rowDroppedSource
  8. event.rowMoved
  9. event.rowNotCloned
  10. event.rowNotMoved
  11. event.rowUndeleted

Each event handler has access to the obj and objOld objects. For example, event.RowClicked() sees only obj object and this is reference to the source row. event.rowMoved() is fired in a moment when dragging starts and in this case, obj is reference to the mini table (previously mentioned) while objOld is reference to the source table row.

REDIPS.drag has a new method: rowOpacity(el, opacity, color) to change color and opacity of the source row and mini table. This way it is only needed to call rowOpacity() method in event handlers to have row effects like in this demo. Here is code for event.rowMoved() used in this demo:

rd.event.rowMoved = function () {
    // set opacity for moved row
    // rd.obj is reference of cloned row (mini table)
    rd.rowOpacity(rd.obj, 85);
    // set opacity for source row and change source row background color
    // rd.objOld is reference of source row
    rd.rowOpacity(rd.objOld, 20, 'White');
    // display message
    msg.innerHTML = 'Moved';
};

REDIPS.drag takes care about background color of table cells and table rows. When dragging begins, color of each table cell is saved to the array and returned in a moment of dropping or highlighting current table row. Source code of REDIPS.drag library with examples can be download from “download icon” below post title. If you want to see more drag and drop examples based on REDIPS.drag, click on Drag and Drop category.

Happy dragging and dropping!

178 thoughts on “Drag and drop table rows with JavaScript”

  1. @zoom – If newly appended row have to become drag-able, it should have rowhandler cell with DIV element. This “special” DIV element should have class=”drag row”. Complete TD will look:

    <td class="rowhandler"><div class="drag row"></div></td>
    

    And after row is added to the table, just call

    REDIPS.drag.enable_drag('init');
    

    … to attach onmousedown event handler to the DIV element. In case of adding new table to the dragging area, REDIPS.drag.init() method should be called to properly initialize internal tables array (and that’s the one of the main parts of REDIPS.drag library).

    If you will have any further questions, please do not hesitate to ask.

  2. Hi,

    if i want to make validation so drag and drop will only possible if the cell in the same row.

    i don’t have any idea. please help.

    thanks

  3. @efs – So you want to drop elements only to source row. Here is how:

    // reference to the REDIPS.drag lib
    var rd = REDIPS.drag;
    // define myhandler_dropped_before event handler
    rd.myhandler_dropped_before = function () {
        // get element position
        var pos = rd.get_position();
        // if target row is not the same as source row then return false
        // (return false will cancel element drop)
        if (pos[1] !== pos[4]) {
            return false;
        }
    };
    

    … and link to the get_position() documentation.

  4. Hi,

    I want to make the undo so that i can revert the last dropped element on that table.Please help me.

    Thanks

  5. Great scripts, but how does one make the drag and drop work on iOS or touchscreen devices?

  6. @Vikas Saini – Here is code for undo option (hope this will be fine):

    // define global variables
    var rd,
        redips_init,
        div = {};
    
    redips_init = function () {
        // reference to the REDIPS.drag library
        rd = REDIPS.drag;
        // initialization
        rd.init();
        // event handler invoked if element is moved from home position.
        rd.myhandler_moved = function () {
            // save element ID and start position to the "div" object
            div.id = rd.obj.id;
            div.position = rd.get_position();
        };
    };
    
    // undo for the last move (function can be called on button click)
    function undo() {
        // move element to the start position
        rd.move_object({
            id: div.id,
            target: div.position
        });
    }
    
    // add onload event listener
    if (window.addEventListener) {
        window.addEventListener('load', redips_init, false);
    }
    else if (window.attachEvent) {
        window.attachEvent('onload', redips_init);
    }
    

    @James – I must admit that I only once tried to play with REDIPS.drag on my HTC. I tried to drag DIV elements but instead of dragging, whole page was scrolled. Did you have the same effect? Maybe DIV element should be pressed for a longer time to allow dragging on Android or other smartphones. Any other comment is more then welcome.

  7. Hi,

    Is it possible to move part of a row?

    Example:

    ---------------------------------------------
    Time  | Task                                |
    ---------------------------------------------
    08:00 | Wash the car                        |
    ---------------------------------------------
    08:15 |                                     |
    ---------------------------------------------
    08:30 | Walk the dog                        |
    ---------------------------------------------
    08:45 | Make coffe                          |
    ---------------------------------------------
    09:00 |                                     |
    ---------------------------------------------
     

    I want to move “Wash the car” to 09:00.

    Kind Regards!

  8. @Ola – Well, REDIPS.drag can’t move a part of table row but you can move content of table cell so it will look like you dragging a part of a row (DIV element can be borderless and styled to fill the table cell). Right below the post title click on Preview link to see examples inside redips2.tar.gz package. I think example03 School timetable is the most similar to shown table in your comment. This is a classic example of timetable with option to save table content.

  9. I was wondering if it was possible to make the whole row the “row handler”? So I might be able to click anywhere on that row to move it. I have no need to move individual cells, only the entire row. Is this possible?

    Btw, your script is amazing.

  10. @dmtdev – Yes it possible and here is the trick:

    <tr>
        <td class="rowhandler"><div class="drag row"></div></td>
        <td class="rowhandler"><div class="drag row"></div></td>
        <td class="rowhandler"><div class="drag row"></div></td>
        <td class="rowhandler"><div class="drag row"></div></td>
        <td class="rowhandler"><div class="drag row"></div></td>
        <td class="rowhandler"><div class="drag row"></div></td>
    </tr>
    
    
    .drag {
        width: 100%;  /* maximum width */
        height: 32px; /* height same as height of table cell */
        border: 0px;  /* no border */
    }
    

    Each table cell should contain “invisible” DIV element. Class name for table cell should be defined as rowhandler. Styles for rowhandler (and row) are not important (it’s only important to define a name). And finally, each DIV element should contain “drag row” class names. If you prepare tables on this way (like placing table cell content in “invisible” DIV elements), each table row will be drag-able on any cell.

  11. HI dbunic,

    I tried out your “code for undo option”,
    I made a close button on dragged element to revert the element on its destination, it is working fine in all browser except “Google Chrome” When I click on the close button the dragged element deviated and goes in wrong cell (mostly in adjacent cells) in same panel ,when we click it again then it goes on right destination.

    I hope you will help me .I ‘ill be great full to you.
    I cant give you the website URL because of security.

    Thanks in advance

  12. @Vikas Saini – I tested my Undo method in Google Chrome and everything works just fine (REDIPS.drag is 4.6.1). I can’t detect error to see where is the problem in JS code. Anyway, I will send you a complete offline example so please make needed changes and send me back. Thank you in advance.

  13. Wow, this is really great work guys. One thing that would be extremely helpful that I can’t seem to get to work on my own. When you move a row around, it makes the underlying row gray based on the set_bgcolor function. The problem is that the actual event that occurs differs depending on whether you’re moving the row down or up. If you move it up, it gets placed ABOVE the current gray row. If you move it down, it gets placed BELOW the current gray row. It isn’t obvious to the end user that this is what’s going to occur.

    The easy way to visually denote where the dragged row is going is by putting a think bright border line between the rows where it will drop. In essence, you put a blue border on the top of the grayed row if you’re dragging a row up, but you’d put a blue border beneath the gray row if you’re moving it down. This will tell the user exactly where it’s going.

    This was my shot at it, but I’m not an expert javascripter, and it only works in Chrome. After setting Y equal to the y coordinate of the original mouse click, I altered set_bgcolor like so:

    for (i = 0; i currentY) {
                // see if currently above or below
                tr.cells[i].style.borderTop = "solid 2px #4b8df9";
            } else {
                tr.cells[i].style.borderBottom = "solid 2px #4b8df9";
            }
        } else {
            tr.cells[i].style.borderTop = "solid 1px #cccbcb";
            tr.cells[i].style.borderBottom = "none";
        }
    }
    

    So, it works well w/ Chrome like I said, but other browsers need the event defined explicitly and return “event is undefined”.

    I’ve been asking around and this is a time sensitive project, so if you have any quick suggestions, I’d really appreciate it!

    Jeremy

  14. The last copy/paste of the code didn’t work very well because of character stripping. Suffice it to say, it said that if Y (the original position) was less than event.clientY (the current position of the mouse), then put the border on the bottom (since the row will be placed below the current grayed row), and the opposite for if it’s being moved up.

  15. Hi ,
    Really this is fantastic i was fully impressed.Great Work…

    I have to multiple cloned value in single cell but repeated cloned should not display in cell. When we drag a repeated clone it should show error message and the cloned should be delete. Is this possible ?

  16. I did end up figuring out how to initialize new rows as draggable, thank you.

    When I trash every last row, I get a blank placeholder row.
    And then when I go to insert a new row to the empty table, it ends up below the placeholder.
    I can then drag it and drop it over the placeholder…

    Is there a way that I could target the blank placeholder row when inserting a new row into a blank table automatically?

    Also, is it possible for draggable rows to be “switchable”? In some of your examples divs can be continuously switching… does this work for rows as well?

    Finally, is there any way around if i do not want to display any messages? I could not get it to work without the hidden input.

  17. Hi dbunic,

    Thanks for your response.Now my undo option is working fine.Thanks again for the immediate response.

  18. @Jeremy – Hope new REDIPS.drag with REDIPS.drag.hover_border (top/bottom TR border) option works like you expected.

    @RajeshKumar – Clone type element can be placed in any TD. In a moment of dragging, element will be cloned (original element will stay intact). Dropping cloned element on top of the original element will automatically delete cloned element. REDIPS.drag has option to delete cloned element if cloned element is dropped outside of any table. This is how cloning is supported in REDIPS.drag library.

    @zoom – I’m glad you solved the problem. Cheers!

    @Vikas Saini – You’re welcome.

Leave a Comment