Drag and drop table rows with JavaScript

More...

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.

Table 1
Drag
and
drop
table
rows
with
REDIPS
lib
Message line
Table 2
Drag
rows
and
table
drop
Message line

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!

This entry was posted on April 6, 2011 and is filed under Drag and Drop, JavaScript

Related posts

166 Responses to Drag and drop table rows with JavaScript

  1. dbunic says:

    @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. efs says:

    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. dbunic says:

    @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. Vikas Saini says:

    Hi,

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

    Thanks

  5. James says:

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

  6. dbunic says:

    @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. Ola says:

    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. dbunic says:

    @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. dmtdev says:

    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. dbunic says:

    @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. Vikas Saini says:

    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. dbunic says:

    @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. Jeremy says:

    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. Jeremy says:

    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. RajeshKumar says:

    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. Pingback: 海雅工作室 – 网络资源 » 拖放表行与JavaScript – REDIPS.drag

  17. zoom says:

    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.

  18. zoom says:

    sorry... * any way around 'input type=hidden id=msg'

  19. Vikas Saini says:

    Hi dbunic,

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

  20. dbunic says:

    @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 Reply

Your email address will not be published. Required fields are marked *

*

In case of posting HTML tags or JavaScript code please convert special characters to HTML entities.
Especially pay attention to convert "<" character to "&lt;" entity!