Make Table Rows Sortable Using jQuery UI Sortable

Add to FacebookAdd to DiggAdd to Del.icio.usAdd to StumbleuponAdd to RedditAdd to BlinklistAdd to TwitterAdd to TechnoratiAdd to Yahoo BuzzAdd to Newsvine

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.

// 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

Advertisements

29 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?

    • Hazzadous Says:

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

  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. 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?

  9. Rodrigo Says:

    Hello,

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

  10. Tim Says:

    Very nice saved me a lot of time πŸ™‚

  11. dchuk Says:

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

  12. deef Says:

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

  13. 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. πŸ™‚ πŸ™‚

  14. Jack Says:

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

  15. dharh Says:

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

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

  16. 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.

  17. chrelad Says:

    Great job, thanks for posting!

  18. Mathew Peterson Says:

    Fantastic, just what I was looking for!

  19. 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..

  20. vikky Says:

    hi,
    can you provide an example page for this.

    thanks,
    Vikky

  21. 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


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: