Ajax pagination
This is the most popular feature request for will_paginate library. Reasons why the core library doesn’t support this are:
- pagination is a concept decoupled from HTTP requests and rendering;
- Ajax pagination is done differently across web frameworks;
- Ajax is done differently across JavaScript libraries (not everyone uses Prototype);
- The JavaScript side of the Ajax pagination concept is not trivial at all.
So the short reason why you can’t get Ajax pagination out-of-the-box with this library is that this kind of functionality belongs to user code.
Here are some examples to get you on the right track.
Warning:
don’t use the “RemoteLinkRenderer” or similar solutions you might find on blogs using Rails’
don’t use the “RemoteLinkRenderer” or similar solutions you might find on blogs using Rails’
link_to_remote
helper. Such solutions are obtrusive and will usually make your app broken for web spiders and difficult to debug.
Basic unobtrusive Ajax pagination for Rails
Let’s suppose you have a search box and you want to paginate search results. The following code assumes that:
- the partial that renders those results is named “search_results”;
- the same partial renders all the results wrapped in a DIV with an ID “results”;
- the “results” DIV also contains the pagination links;
- you have a graphic progress indicator (a “spinner”) saved in “images/spinner.gif”.
# app/views/posts/_search_results.html.erb
<div id="results">
<% for post in @posts %>
... render each post ...
<% end %>
<%= will_paginate @posts %>
</div>
First of all, make sure your controller responds to Ajax requests by updating the “results” DIV :
# app/controllers/posts_controller.rb
def index
@posts = Post.paginate :page => params[:page]
respond_to do |format|
format.html
format.js {
render :update do |page|
# 'page.replace' will replace full "results" block...works for this example
# 'page.replace_html' will replace "results" inner html...useful elsewhere
page.replace 'results', :partial => 'search_results'
end
}
end
end
Next, the unobtrusive JavaScript code:
# public/javascripts/application.js
document.observe("dom:loaded", function() {
// the element in which we will observe all clicks and capture
// ones originating from pagination links
var container = $(document.body)
if (container) {
var img = new Image
img.src = '/images/spinner.gif'
function createSpinner() {
return new Element('img', { src: img.src, 'class': 'spinner' })
}
container.observe('click', function(e) {
var el = e.element()
if (el.match('.pagination a')) {
el.up('.pagination').insert(createSpinner())
new Ajax.Request(el.href, { method: 'get' })
e.stop()
}
})
}
})