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 Show archive.org snapshot . 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 ui.helper.is('tr:first-child') # Design fix
# Fix placeholder height
sortable.containment[3] += (draggedItemHeight - ui.placeholder.height())
ui.placeholder.height draggedItemHeight
Styling
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