views:

1254

answers:

7

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.

+2  A: 

I've used the Yahoo User Interface library to do this before:

http://developer.yahoo.com/yui/dragdrop/

bobwienholt
A: 

Scriptaculous sortables seems like the way to go since it's built in. http://github.com/madrobby/scriptaculous/wikis/sortable

Bryan Woods
It doesn't work for tables at this time.
Jay Stramel
+1  A: 

The Yahoo interface was easier than I expected, had something snazzy working in less than four hours.

Jeff
+2  A: 

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);
Ates Goral
Honestly, I love MooTools. It isn't as widely used as the others but the library is great!
Abyss Knight
+2  A: 

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.

Mark S.
+2  A: 

I like jQuery http://docs.jquery.com/UI/Sortables

$("#myList").sortable({});

You will need to write some code to persist it but it isn't that tough.

Kyle
A: 

You may look at Sortable Lists

humble_coder