Posted over 1 year ago. Visible to the public.

UI Sortable on table rows with dynamic height

UI sortable helps reordering items with drag 'n drop. It works quite fine.

Proven configuration for sorting table rows

When invoking the plugin, you may pass several options. This set is working fine with table rows:

$tbody.sortable # Invoke on TBODY when ordering tables axis: 'y' # Restrict drag direction to "vertically" cancel: 'tr:first-child:last-child, input' # Disable sorting a single tr to prevent jumpy table headers containment: 'parent' # Only drag within this container placeholder: 'ui-sortable-placeholder' # Prevent visibility:hidden stop: onSortEnd # See below start: onSortStart # See below below

Inside onSortEnd(), you'll react on the reordering. Within forms, you may want to update hidden position fields in the form:

onSortEnd = -> positionFields = element.find('input[id$=position]') for position, i in positionFields $(position).val i + 1

Outside of forms, within lists, you may want to manually post the new positions to some URL:

onSortEnd = -> ordered_ids = element.sortable('serialize') $.post '/some/url', ordered_ids

The serialize method aggregates the id's of all sortable items (i.e. table rows), which are expected in format <set name>_<id>. For example, tr#position_13 and tr#position_15 will be turned into position[]=13&position[]=15, which neatly resolves to params[:position] == [13, 15] in Rails.

Broken placeholder height

When a dragged row does not have a set height but rather adjusts to its content, the placeholder row does not get the height of the currently dragged item. Further, when using "containment" (which limits dragging to within a given container), it uses wrong containment limits.

You can fix this in the onSortStart callback:

onSortStart = (event, ui) -> sortable = $(this).sortable('instance') # Obtain UI sortable instance draggedItemHeight = ui.helper.height() draggedItemHeight -= 1 if'tr:first-child') # Design fix # Fix placeholder height sortable.containment[3] += (draggedItemHeight - ui.placeholder.height()) ui.placeholder.height draggedItemHeight


Finally, here are some subtle, but nice styles:

.ui-sortable-handle &:hover cursor: grab // Applied during the drag &.ui-sortable-helper display: table // Maintain table cell widths opacity: 0.7 transition: opacity 0.3s cursor: grabbing // Fix design issue with UI sortable, causing the thead border-bottom to grow // when the first table row is dragged tr.ui-sortable-helper:first-child + tr > td border-top: none
Growing Rails Applications in Practice
Check out our new e-book:
Learn to structure large Ruby on Rails codebases with the tools you already know and love.

Author of this card:

Dominik Schöler
Last edit:
over 1 year ago
by Dominik Schöler
About this deck:
We are makandra and do test-driven, agile Ruby on Rails software development.
License for source code
Posted by Dominik Schöler to makandropedia