Lately, I seem to be on a tear here with my Ruby on Rails development related posts. I suppose its more for my own documentation, but if it helps someone else out with their own development struggles, even better.
Today, I wanted to find a solution to updating pagination using AJAX. My issue was I use AJAX to update the DOM to remove an item when its deleted. However, the pagination doesn’t update and the listings don’t adjust as you delete them from the middle of the list. My solution, while not rocket science, I think is pretty cool. Basically, just keep using AJAX!
The first thing I need is a div to encapsulate my list. Something like:
<div id="my_list"> <%= render :partial => "items", :collection => items %> <%= will_paginate items, :renderer => 'ItemLinkRenderer' %> </div>
Obviously, that’s my original list inside the my_list
div. I’ll get to what ItemLinkRenderer is in a big.
I delete my items from the list by updating the dom from within the delete action. So, something like this:
@item = Item.find(params[:id]) if !@item.nil? @item.destroy render(:update) { |page| page.remove dom_id(@item) } end
This should look pretty straight forward. Delete the item from the database, then remove it from the current document.
But what about updating the pagination and the list? We can remove an item, but how do we adjust the displayed list? Well, just fetch the list of items again.
@items = Item.paginate :all, :page => params[:page], :per_page => 10 if @items.length > 0 page.replace_html "my_items", :partial => "items", :locals => {:items => @items} else page.replace_html "my_items", "<p>You have no items.</p>" end
Ok, so we can render the items. But, if you put this in, then start deleting items, you’ll notice your pagination links get messed up and you have your delete action in the URL. This isn’t good, but, like I mentioned earlier, this is where ItemLinkRenderer comes in. You can define a helper class called ItemLinkRenderer (in item_link_renderer.rb) to render your links properly.
class ItemLinkRenderer < WillPaginate::LinkRenderer def page_link_or_span(page, span_class = 'current', text = nil) text ||= page.to_s if page and page != current_page @template.link_to text, :controller => "items", :action => "list", :page => page else @template.content_tag :span, text, :class => span_class end end end
This will render your pagination links properly. Hopefully this works out well for anyone who stumbles upon this. Let me know if it does or if you find any errors with what I’ve presented.