Foliotek Development Blog

Make Table Rows Sortable Using jQuery UI Sortable

by Brian Grinstead

So you want to make table rows sortable using jQuery UI? Luckily, the Sortable interaction does most of the work for you.

But there’s a catch: one problem that I ran into when implementing this (with UI version 1.7) was the cell widths of the row would collapse once I started dragging it.

Suppose you have a table of data, like this one:


<table id="sort" class="grid" title="Kurt Vonnegut novels">
	<thead>
		<tr><th>Year</th><th>Title</th><th>Grade</th></tr>
	</thead>
	<tbody>
		<tr><td>1969</td><td>Slaughterhouse-Five</td><td>A+</td></tr>
		<tr><td>1952</td><td>Player Piano</td><td>B</td></tr>
		<tr><td>1963</td><td>Cat's Cradle</td><td>A+</td></tr>
		<tr><td>1973</td><td>Breakfast of Champions</td><td>C</td></tr>
		<tr><td>1965</td><td>God Bless You, Mr. Rosewater</td><td>A</td></tr>
	</tbody>
</table>

Your first attempt to make it sortable might look like this:


$("#sort tbody").sortable().disableSelection();

And it actually works, but there is a bit of a problem. The cell widths seem to be collapsing once you start dragging a row (notice how close the “C” cell is to the “Breakfast of Champions” cell). It looks like this:

Sortable row collapsed widths

The problem has to do with the helper object. The helper object is basically the DOM element that follows the cursor during the drag event. When it is created by default, the cells collapse to the size of the content inside of them.

You can specify a function that returns a jQuery object to create a custom helper object. By creating a function that will keep the cell widths consistent, this problem can be fixed.

Update: I have posted a jsFiddle demo of table sorting with jQuery UI to show how the fix works. There is another fix, proposed on StackOverflow that includes cloning the original row (to not set the width permanently). This is also included in the jsFiddle.

// Return a helper with preserved width of cells
var fixHelper = function(e, ui) {
	ui.children().each(function() {
		$(this).width($(this).width());
	});
	return ui;
};

$("#sort tbody").sortable({
	helper: fixHelper
}).disableSelection();

Now it works as expected:
Sortable row fixed

Tags: , , , , , , , , ,

« »

50 Responses to “Make Table Rows Sortable Using jQuery UI Sortable”

  1. Brian Grinstead » Blog Archive » Make Table Rows Sortable Using jQuery UI Sortable Says:

    [...] wrote an article over on the LANIT Development blog about a problem that I ran into when trying to set up a basic [...]

  2. Gerald Says:

    good job,
    but i”ve a question, how do you implement the placeholder?

  3. Jason Says:

    This was incredibly useful! Thanks for figuring this out.

  4. Jason Dusek Says:

    How does this code actually work?

    $(this).width($(this).width());

    How does setting the width back to itself do anything at all?

  5. Mauricio Wolff Says:

    veeeeeeeeeeeery nice… tks

  6. Manic Says:

    There is a problem when formating table using css with border-collapse: collapse. It doubles the border on sort. Do you know jow to fix this?

  7. Hazzadous Says:

    Note that there is a ”forceHelperSize” now.

  8. Hazzadous Says:

    width( ) returns the calculated width in pixels. By setting width with this calculated width, you are explicitly stating its width.

  9. Hazzadous Says:

    Which on closer inspection, doesn”t help :)

  10. Wills Bithrey Says:

    I can”t seem to get this to work? my html is as follows:

    PositionCarDriverFastest Lap

    1Lamborghini Gallardo SWills1:38.277
    2Lamborghini MurcielagoNick1:38.392
    3Audi R8 V10Aidy1:37.938
    4Porche 911 GT2Phil1:38.000
    5Ford GTMatt1:36.814

    and in my jQuery script I have:

    $(document).ready(function() {
    $(”.sortable”).sortable({
    helper: fixHelper,
    cursor: ”move”,
    placeholder: ”ui-state-highlight”,
    axis: ”y”,
    update: function(e, ui) {
    $el = $(ui.item);
    $el.effect(“highlight”,{},2000);
    $(“.sortable tr”).each(
    function(currentIndex) {
    $(this).find(“td:first”).text(this.rowIndex);
    });
    href = ”/myReorderFunctionURL/”;
    $(this).sortable(“refresh”);
    sorted = $(this).sortable(“serialize”, ”id”);
    $.ajax({
    type: ”POST”,
    url: href,
    data: sorted,
    success: function(msg) {
    //do something with the sorted data
    }
    });
    }
    }).disableSelection();
    // Return a helper which preserves the width of the table cells
    var fixHelper = function(e, ui) {
    ui.children().each(function() {
    $(this).width($(this).width());
    });
    return ui;
    };
    });

    I tried removing most of the jQuery and just keeping the minimal required but still my table rows cells collapse :(.

    Any ideas?

  11. Wills Bithrey Says:

    It would appear I fail at posting HTML ;)

    My HTML is here: http://pastebin.com/m211d85d6

  12. Wills Bithrey Says:

    Never mind, I found the answer here: http://stackoverflow.com/questions/1307705/jquery-ui-sortable-with-table-and-tr-width

    Works Perfectly!
    Thanks to both Brian Grinstead and Dave Miller for this awesome solution :)

  13. Brian Grinstead Says:

    Glad it worked! I will make a note of his method of cloning the row to prevent having explicit widths set on the original row.

  14. Rodrigo Says:

    Hello,

    How we can get the serialized values in this case?
    thanks

  15. Tim Says:

    Very nice saved me a lot of time :)

  16. dchuk Says:

    oh man, this saved me a hell of a lot of time, thanks for doing this! good work

  17. deef Says:

    Thanks for posting this. Was starting to loose time on this one.

  18. Rajesh Says:

    I was doing R&D for the same thing and was not getting success. Your code works and it saved my time. Many many thanks to you. :) :)

  19. Jack Says:

    Thanks much, this saved me from having to dig into the root of this problem. Much appreciated!!!

  20. dharh Says:

    Ive found that this isn”t usually necessary if you use sortable like this:

    $(“.sortable tbody”).sortable({
    items: “tr”
    });

  21. Vlad Nastasiu Says:

    @dharh that doesn”t work, still messes up the data inside the tr.
    @Brian using your fixHelper function hides the element I want to drag… I have the trs inside a tbody and it”s the tbody that I make sortable.

  22. Vlad Nastasiu Says:

    Yet, the answer below works better as @Wills suggested.
    http://stackoverflow.com/questions/1307705/jquery-ui-sortable-with-table-and-tr-width

  23. chrelad Says:

    Great job, thanks for posting!

  24. Mathew Peterson Says:

    Fantastic, just what I was looking for!

  25. Amir Says:

    What data do you send to update?
    How does this code work?
    $(this).sortable(?serialize?, ?id?);

    I try to get any data for the sorted and I can not get any..

  26. Brian Grinstead Says:

    Amir,
    Here is documentation for the serialize method: http://jqueryui.com/demos/sortable/#method-serialize

    I believe that by default, serialize will use the “id” attribute for each item with the output. The second parameter can change which attribute it looks at, but I think in the latest version, the second parameter needs to be an object hash, like { key: ”id” }.

  27. vikky Says:

    hi,
    can you provide an example page for this.

    thanks,
    Vikky

  28. Brian Grinstead Says:

    Vikky, I made an example of jQuery table row sorting for you to help show what is going on and how to fix it. If you click the “Edit with JSBin” link in the top right corner of the page, you can make changes to the page.

  29. Web Design Leicester Says:

    Many thanks, I found this example to be better than the one that clones the elements which led to unexpected side effects

  30. beejay Says:

    yeahhhh!!!!!! thank””s a lot!!!!!!!!!!!!!!

  31. Kompass Says:

    Kompass…

    [...]Foliotek Development Blog » Blog Archive » Make Table Rows Sortable Using jQuery UI Sortable[...]…

  32. Kevin Says:

    Awesome! This turned a problem that would have taken hours to solve into a completely trivial task. Thank you very much!

  33. Devin Walker Says:

    Good post, helped me for my need. Showing data in tables that needs sorting. This fixed that nasty collapse issue with no effort. Thanks for supporting the community.

  34. Euronymous Says:

    Thanks man! :)

  35. Boidy Says:

    Incredibly useful and easy to implement. Thanks.

  36. Alejandro Says:

    I”m noticing a problem on my own implementation, and I can reproduce it on the jsFiddle, which is that there is a spacing issue (a separation between two rows) when I repeatedly drag the “2nd to last row” to be the last row. To really see the separation, do that like 20 times or so. This shows up the most in the “Modified fix”, and only a small gap appears in the “original fix”. Worst thing is, I don”t know what the space is; it looks like padding or margin on one of the rows, but using Firebug there”s no such space at all.

  37. Stefan Says:

    Works well – thanks.
    But if I limit the axis to “y” safari (OSX, latest regular Version) produces odd errors.
    With the first and last it always works, but any in between places the helper object outside the right table-border. It seems that Safari is somehow changing the table-width when you add the placeholder. The error is pretty random.
    If you insert the option ” axis: ”y” ” into your example you can see the error in safari too.
    Any idea how to fix this or what the cause of this is?

  38. gkohen Says:

    How do you deal with two of this sortable tables that are connected to each other with ”connectWith”. This issue starts with one of the table starts as being empty. Some of the solutions starts with forcing a min-size on the tbody (Not working) or having the sortable selector by ”mytable” rather than ”mytable tbody” and then the items selector being ”tbody >tr”. That seems to have problems with dragging items back and forth between the two tables. Has anyone implemented it successfully?

  39. Brian Grinstead Says:

    gkohen,
    Can you set up a jsbin example with this situation?

  40. Guilherme Carlos Says:

    Thank you so much! This will help me a lot :-D

    Thanks from Brazil

  41. jack Says:

    Great stuff man! I don”t know how u came up with “$(this).width($(this).width())” – but it works! Cheers!

  42. waqas Says:

    works perfectly fine. Thanks a lot

  43. Michael Says:

    If you have a checked radio button inside your table cells that you are sorting, the ”fixHelperModified” function will cause the radio button to be unchecked. The ”fixHelper” function does not cause this behavior.

  44. Darshan Says:

    It does work perfectly. Thanks

  45. Dacccs Says:

    Good work! I love this script. :)

  46. Grails remoteFunction after jQuery sortable Says:

    [...] Which I found on here http://www.foliotek.com/devblog/make-table-rows-sortable-using-jquery-ui-sortable/ [...]

  47. Leo Maverick Says:

    Works perfectly for me, thanks.
    But on question.. why it didm”t work when i”m using containment the restrict the movement area?

  48. Walter Otsyula Says:

    You da man! Thanks! Now I can use this to impress others ^^

  49. Golak Jena Says:

    Works perfectly. Very Nice job. Thanks lot…

  50. Tom Lev Says:

    Very easy! Thanks!

Leave a Reply