I’ve been using JQuery for a while now and really agree with its tag line that it’s the “The Write Less, Do More, JavaScript Library”. We’ve also got this code for dragging and dropping table rows that has proved very popular, so it seemed natural to combine the two and wrap up the table drag and drop as a JQuery plugin.

Why have another plugin?

Dragging and dropping rows within a table can’t be handled by general purpose drag and drop utilities for a number of reasons, not least because you need to move the whole row, not just the cell that receives the mouse events. Re-parenting the row also requires specific code. Sadly also, effects like fadeIn and fadeOut don’t work well with table rows on all browsers, so we have to go for simpler effects.

What does it do?

This TableDnD plugin allows the user to reorder rows within a table, for example if they represent an ordered list (tasks by priority for example). Individual rows can be marked as non-draggable and/or non-droppable (so other rows can’t be dropped onto them). Rows can have as many cells as necessary and the cells can contain form elements.

How do I use it?

  1. Download Download jQuery (version 1.2 or above), then the TableDnD plugin (current version 0.7).
  2. Reference both scripts in your HTML page in the normal way.
  3. In true jQuery style, the typical way to initialise the tabes is in the $(document).ready function. Use a selector to select your table and then call tableDnD(). You can optionally specify a set of properties (described below).
1 One some text
2 Two some text
3 Three some text
4 Four some text
5 Five some text
6 Six some text

The HTML for the table is very straight forward (no Javascript, pure HTML):

<table id="table-1" cellspacing="0" cellpadding="2">
    <tr id="1"><td>1</td><td>One</td><td>some text</td></tr>
    <tr id="2"><td>2</td><td>Two</td><td>some text</td></tr>
    <tr id="3"><td>3</td><td>Three</td><td>some text</td></tr>
    <tr id="4"><td>4</td><td>Four</td><td>some text</td></tr>
    <tr id="5"><td>5</td><td>Five</td><td>some text</td></tr>
    <tr id="6"><td>6</td><td>Six</td><td>some text</td></tr>
</table>

To add in the “draggability” all we need to do is add a line to the $(document).ready(...) function
as follows:

<script type="text/javascript">
$(document).ready(function() {
    // Initialise the table
    $("#table-1").tableDnD();
});
</script>

In the example above we’re not setting any parameters at all so we get the default settings. There are a number of parameters you can set in order to control the look and feel of the table and also to add custom behaviour on drag or on drop. The parameters are specified as a map in the usual way and are described below:

onDragStyle
This is the style that is assigned to the row during drag. There are limitations to the styles that can be associated with a row (such as you can’t assign a border—well you can, but it won’t be displayed). (So instead consider using onDragClass.) The CSS style to apply is specified as a map (as used in the jQuery css(...) function).
onDropStyle
This is the style that is assigned to the row when it is dropped. As for onDragStyle, there are limitations to what you can do. Also this replaces the original style, so again consider using onDragClass which is simply added and then removed on drop.
onDragClass
This class is added for the duration of the drag and then removed when the row is dropped. It is more flexible than using onDragStyle since it can be inherited by the row cells and other content. The default is class is tDnD_whileDrag. So to use the default, simply customise this CSS class in your stylesheet.
onDrop
Pass a function that will be called when the row is dropped. The function takes 2 parameters: the table and the row that was dropped. You can work out the new order of the rows by using
table.tBodies[0].rows.
onDragStart
Pass a function that will be called when the user starts dragging. The function takes 2 parameters: the table and the row which the user has started to drag.
scrollAmount
This is the number of pixels to scroll if the user moves the mouse cursor to the top or bottom of the window. The page should automatically scroll up or down as appropriate (tested in IE6, IE7, Safari, FF2, FF3 beta)

This second table has has an onDrop function applied as well as an onDragClass. The javascript to set this up is as follows:

$(document).ready(function() {

	// Initialise the first table (as before)
	$("#table-1").tableDnD();

	// Make a nice striped effect on the table
	$("#table-2 tr:even').addClass('alt')");

	// Initialise the second table specifying a dragClass and an onDrop function that will display an alert
	$("#table-2").tableDnD({
	    onDragClass: "myDragClass",
	    onDrop: function(table, row) {
            var rows = table.tBodies[0].rows;
            var debugStr = "Row dropped was "+row.id+". New order: ";
            for (var i=0; i<rows.length; i++) {
                debugStr += rows[i].id+" ";
            }
	        $(#debugArea).html(debugStr);
	    },
		onDragStart: function(table, row) {
			$(#debugArea).html("Started dragging row "+row.id);
		}
	});
});
1 One
2 Two
3 Three
4 Four
5 Five
6 Six
7 Seven
8 Eight
9 Nine
10 Ten
11 Eleven
12 Twelve
13 Thirteen
14 Fourteen

What to do afterwards?

Generally once the user has dropped a row, you need to inform the server of the new order. To do this, we’ve added a method called serialise(). It takes no parameters but knows the current table from the context. The method returns a string of the form tableId[]=rowId1&tableId[]=rowId2&tableId[]=rowId3...
You can then use this as part of an Ajax load.

This third table demonstrates calling the serialise function inside onDrop (as shown below). It also demonstrates the “nodrop” class on row 3 and “nodrag” class on row 5, so you can’t pick up row 5 and
you can’t drop any row on row 3 (but you can drag it).

    $('#table-3').tableDnD({
        onDrop: function(table, row) {
            alert($.tableDnD.serialize());
        }
    });

Ajax result

Drag and drop in this table to test out serialise and using JQuery.load()

1 One
2 Two
3 Three (Can’t drop on this row)
4 Four
5 Five (Can’t drag this row)
6 Six

This table has multiple TBODYs. The functionality isn’t quite working properly. You can only drag the rows inside their own TBODY, you can’t drag them outside it. Now this might or might not be what you want, but unfortunately if you then drop a row outside its TBODY you get a Javascript error because inserting after a sibling doesn’t work. This will be fixed in the next version. The header rows all have the classes “nodrop” and “nodrag” so that they can’t be dragged or dropped on.

H1 H2 H3
4.1 One
4.2 Two
4.3 Three
4.4 Four
4.5 Five
4.6 Six
H1 H2 H3
5.1 One
5.2 Two
5.3 Three
5.4 Four
5.5 Five
5.6 Six
H1 H2 H3
6.1 One
6.2 Two
6.3 Three
6.4 Four
6.5 Five
6.6 Six

The following table demonstrates the use of the default regular expression. The rows have IDs of the form table5-row-1, table5-row-2, etc., but the regular expression is /[^-]*$/ (this is the same as used in the NestedSortable plugin for consistency). This removes everything before and including the last hyphen, so the serialised string just has 1, 2, 3 etc. You can replace the regular expression by setting the serializeRegexp option, you can also just set it to null to stop this behaviour.

    $('#table-5').tableDnD({
        onDrop: function(table, row) {
            alert($('#table-5').tableDnDSerialize());
        },
        dragHandle: ".dragHandle"
    });
1 One some text
2 Two some text
3 Three some text
4 Four some text
5 Five some text
6 Six some text

In fact you will notice that I have also set the dragHandle on this table. This has two effects: firstly only the cell with the drag handle class is draggable and secondly it doesn’t automatically add the cursor: move style to the row (or the drag handle cell), so you are responsible for setting up the style as you see fit.

Here I’ve actually added an extra effect which adds a background image to the first cell in the row whenever you enter it using the jQuery hover function as follows:

    $("#table-5 tr").hover(function() {
          $(this.cells[0]).addClass('showDragHandle');
    }, function() {
          $(this.cells[0]).removeClass('showDragHandle');
    });

This provides a better visualisation of what you can do to the row and where you need to go to drag it (I hope).

Tagged with:
 

880 Responses to Table Drag and Drop JQuery plugin

  1. Daevid Vincent says:

    Also, for the ajaxTest.php since you send the data as a big string (instead of a JS JSON or native array), I had to add parse_str() to convert back to a PHP array to get this to work.

    parse_str($_REQUEST['array_string']);
    var_dump($table-3);
    foreach($table-3 as $value) echo “$value”;

  2. Happy says:

    I love this script, but one question though, how do I get the results into a database so where row id is what the new order will change and this is replicated for every row?
    Thanks

  3. David says:

    Does this plugin work with touch events on the iphone / ipad? If so, how is that implemented?

  4. sheraz says:

    Hi, i am working on a project and my requirement is that i want to limit the drag n drop of rows. What i want to do is that some questions are answered and unanswered. if row 2 is unanswered and row 5 is answered then the row 2 can be dragged below the row 5 but any row below the row 5 cannot be dragged above the row 5. I have implemented the logic but unable to understand how to limit the drag n drop at the time of dragging that it will not drag above the row 5. Please guide me how i can do this.

  5. Shawn says:

    In regards to the javascript error that is thrown when you try and drag a row into another tbody (see table-4 example), you can add a try/catch block to suppress that error and just return false when that error is thrown.

  6. dky says:

    is there a way to access the row dragged with that dropped?
    Example:
    If I replace row1 with row3, can i get both rows?
    Thanks

    • denish says:

      Hi Erik,

      You should be able to bind a function to onDragStart and then you’ll be given the current row. If you use $(row).index at that point and store you should have the info you need?

      Denis

  7. Newbie says:

    I am beginer in this field and it does not work for me.

    Here is my code:

    Example 0: Minimal steps to enable content dragging in table

    $(document).ready(function() {
    // Initialise the table
    $("#table-1").tableDnD();
    });

    1Onesome text
    2Twosome text
    3Threesome text
    4Foursome text
    5Fivesome text
    6Sixsome text

    The paths to both js files are valid.

    Am I missing something?
    Thanks for you time and answer.

    • Newbie says:

      Example 0: Minimal steps to enable content dragging in table

      $(document).ready(function() {
      // Initialise the table
      $(“#table-1″).tableDnD();
      });

      1Onesome text
      2Twosome text
      3Threesome text
      4Foursome text
      5Fivesome text
      6Sixsome text

  8. John says:

    Hi,
    I have two td in tr and i want to drag and drop in same td, so anyone can help me.

    Thanks.

  9. Gabriela Dan says:

    I used yhis plugin without any issues until now. I’m using the same code in 2 different pages and in first case is working, in second, it seems the onDrop function is not trigger. I checked and each tr has an unique id, the id of the table is unique, the js files are included correct. The single difference between that pages is the position of the table.

    first page (working):

    second page (NOT working):

    and jQuery the code for both cases:

    $(document).ready(function() {
    $('#sortable').tableDnD({
    onDrop: function(table, row) {
    var rows = table.tBodies[0].rows;
    var newOrder = "";
    orderPos = 0;
    for (var i=0; i 0) {
    orderPos ++;
    newOrder += orderPos+'-'+rows[i].id+";";
    }
    }
    $.ajax({
    type: "post",
    url: "backend.php",
    data: { 'section': 'oferte', 'enforcer': 'reorder', 'newOrder':newOrder},
    error: function() {
    console.log("theres an error with AJAX");
    },
    success: function() {
    //console.log("Saved.");
    }
    });

    },
    dragHandle: ".dragHandle"
    });
    });

    I made something wrong? Something missing?
    Thank you

  10. Gabriela Dan says:

    Don’t saved the most important thing (html code from the pages) :)

    first page (is working)

    second page (NOT working):

    • Gabriela Dan says:

      I removed the close tag…. I don’t know why not saveing the entire message :(

      first page (is working)

      second page (NOT working):

      • Gabriela Dan says:

        It seems the html->table structure can’t be saved…. the difference is that in the working case, the sortable table is directly in , in the second case, the table is inside a of other tables.

        This shouldn’t be a problem, because in jQuery I used id (“#sortable”), and yet… doesn’t work

        • Gabriela Dan says:

          Don’t saved the most important thing (html code from the pages) -> last attempt

          first page (is working)
          form id=”myForm”
          table id=”sortable”
          tbody
          tr id=”1″ ; td ; tr
          tr id=”2″ ; td ; tr
          tbody
          table
          form

          second page (NOT working):

          form id=”myForm”
          table id=”my_other_table”
          tbody
          tr id=”someid”; td ; td ; tr
          tr id=”otherid”
          td colspan=”2″
          table id=”sortable”
          tbody
          tr id=”1″ ; td ; tr
          tr id=”2″ ; td ; tr
          tbody
          table
          td
          tr
          tbody
          table
          form

  11. nofree says:

    On click of cancel button on JavaScript confirm box, how can I cancel sortable?

  12. Ruben Bridgewater says:

    Hey,

    I just wanted to point out that you can fix some issues very easy.

    In version 0.7 you used $(“…”).tableDnDUpdate() which is not needed. I recommend to use delegated events instead.

    And your problem with the tbodys is also easy to solve: Just call one TableDnD on every tbody or you got to rewrite the code so you use tbodys instead of the hole table internally.

    I used version 0.4 and just rewrote the makeDraggable function:

    makeDraggable: function(table) {
    var config = table.tableDnDConfig;
    // Delegate the TR eventlistener to the table body so new elements will be draggable
    $(table).delegate(“tr”, “mousedown”, function(ev) {
    … your code …
    }).css(“cursor”, “move”); // Store the tableDnD object;
    },

    Delegate is usable since jQuery 1.4.3. If you use 1.7 or newer you should use “on” instead.

    Greetings

  13. Britinusa says:

    Great plugin. Tested in all the major browsers.

    Cannot get it to work on a Tablet (Android or WinRT) but most likely because the OS is grabbing the Touch event.

    Looking to adding up/down images to each row and only show them if the Touch is detected, then switch to a click event on those images.

    Any assist would be awesome.

    Thanks Dennis.

    paul

  14. kanuru sagar says:

    hi,
    I need tablednd for below table

    166
    266
    366
    466
    566
    666

  15. Cyrille.T says:

    Hi,
    Nice plugin ; I try to use the exemple #5 and i have a question :

    Will be there a solution to fix a column with a ‘nodrag’ option on each to have a ranking (id 1, 2, 3… on each ‘nodraggable’ column) and an ‘draggable’ column with another id ?

    Greetings

  16. Daniel says:

    Is there way to make specific row not only not-draggable but always fixed to its given position?

  17. George says:

    I see the examples don’t show any column work… what if you want to drag your value not only up and down rows, but also across to certain columns, and save the value in the database? Can this plug in do the trick?

  18. Ras says:

    Hello,
    is there a way to use this great plugin in nested tables ?
    e.g.: I have one big table that contains other tables in her own cells…
    Row of little tables in cell should be draggable, but also the rows of the big table should be draggable …

    Thank you for any suggestion !!

    • Rachana says:

      Here you go.

      ↓↑

      ↓↑12
      ↓↑34
      ↓↑56

      ↓↑

      ↓↑ab
      ↓↑cd

      ↓↑test

      $(function(){

      $(“#t1″).tableDnD({

      onDrop: function(table, row) {
      alert($(‘#t1′).tableDnDSerialize());
      },
      dragHandle: “.dragHandle”
      });

      $(“#t2″).tableDnD({

      onDrop: function(table, row) {
      alert($(‘#t2′).tableDnDSerialize());
      },
      dragHandle: “.dragHandle1″
      });
      $(“#t3″).tableDnD({

      onDrop: function(table, row) {
      alert($(‘#t3′).tableDnDSerialize());
      },
      dragHandle: “.dragHandle1″
      });

      });

  19. pankaj says:

    i want to drug a row to another table row. how it can be possible using jquery?
    please explain deeply. i am new in this field.
    another thing you have a example of eCommerce project. i want to make similar type of project. so please tell me?
    send me email notification please.

  20. Arun Jain says:

    I am saving the row order in hidden variable. I want to set the hidden variable during page load also(suppose the user did not changed the order).

    How I can trigger drop event for the table.

    Please suggest.

  21. Edwin says:

    I want to cancel(remove drag and drop) ater click in cancel button. How can I reset the table with Data and remove or Disable drag and drop?

  22. Júnior Mendonça says:

    Hey dude! Awesome work! Contratulations!

  23. Seçkin Başköy says:

    Hi,

    $(function() {
    
        $("#ordertable tbody").tableDnD({
            onDrop: function(table, row) {
                var orders = $.tableDnD.serialize();
                $.post('orderall.php', { orders : orders });
                window.location.href=window.location.href;
            }
        });
    
    });
    

    This script is not work on firefox. How can I fix it? (Its working well with internet explorer.

    • denish says:

      Have you tried using Firebug to see what the console says and if there are any errors? You can also use it to put break points and check the value of (for example) the orders variable.

  24. Scott says:

    Great script although I noticed an issue with it when using the jQuery noConflict as I use cheetah and this uses $ as a template variable. Lines 108 and 261 look like they need tweaking to substitute $ for jQuery. Well that’s what I did and it works a treat!

  25. kanuru sagar says:

    i wanna drag two tables tr with similar index at a time .It is possible using tablednd in easy-ui datagrid.

Leave a Reply

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

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>