I have a Ruby on Rails application that I'm writing where a user has the option to edit an invoice. They need to be able to reassign the order of the rows. Right now I have an index column in the db which is used as the default sort mechanism. I just exposed that and allowed the user to edit it.
This is not very elegant. I'd like the user to be able to drag and drop table rows. I've used Scriptaculous and Prototype a bit and am familiar with them. I've done drag and drop lists, but haven't done table rows quite like this. Anyone have any suggestions for not only reordering but capturing the reorder efficiently?
Also, the user can dynamically create a new row in JS right now, so that row has to be reorderable as well.
Bonus points if it can be done with RJS instead of direct JavaScript.
I've used the Yahoo User Interface library to do this before:
http://developer.yahoo.com/yui/dragdrop/
MooTools sortables are actually better than script.aculo.us because they are dynamic; MooTools allows the addition/removal of items to the list. When a new item is added to a script.aculo.us sortable, you have to destroy/recreate the sortable to make the new item sortable. There'll be a lot overhead in doing so if the list has many elements. I had to switch from script.aculo.us to the more lightweight MooTools just because of this limitation and ended up being extremely happy with that decision.
The MooTools way of making a newly added item sortable is just:
sortables.addItems(node);
Okay, I did some more scouring and figured out something that seems to mostly be working.
edit.html.erb:
...
<table id="invoices">
<thead>
<tr>
<th>Id</th>
<th>Description</th>
</tr>
</thead>
<tbody id="line_items">
<%= render :partial => 'invoice_line_item', :collection => @invoice.invoice_line_items.sort %>
</tbody>
</table>
<%= sortable_element('line_items', {:url => {:action => :update_index}, :tag => :tr, :constraint => :vertical}) -%>
...
app/controllers/invoices.rb
...
def update_index
params["line_items"].each_with_index do |id, index|
InvoiceLineItem.update(id, :index => index)
end
render :nothing => true
end
...
The important part is :tag => :tr in "sortable_element" and params["line_items"] -- this gives the new list of ids and is triggered on the drop.
Detriments: Makes the AJAX call on drop, I think I'd prefer to store the order and update when the user hits "save". Untested on IE.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With