How to Implement ajax pagination with will_paginate gem
Create a new helper (ex. app/helpers/will_paginate_helper.rb) with the following content:
module WillPaginateHelper
class WillPaginateJSLinkRenderer < WillPaginate::ActionView::LinkRenderer
def prepare(collection, options, template)
options[:params] ||= {}
options[:params]['_'] = nil
super(collection, options, template)
end
protected
def link(text, target, attributes = {})
if target.is_a? Fixnum
attributes[:rel] = rel_value(target)
target = url(target)
end
@template.link_to(target, attributes.merge(remote: true)) do
text.to_s.html_safe
end
end
end
def js_will_paginate(collection, options = {})
will_paginate(collection, options.merge(:renderer => WillPaginateHelper::WillPaginateJSLinkRenderer))
end
end
Then in your view use this tag for ajax pagination:
<%= js_will_paginate @recipes %>
Remember that the pagination links will include existing params of the url, you can exclude these as shown below. This is standard will paginate functionality:
<%= js_will_paginate @recipes, :params => { :my_excluded_param => nil } %>
Hope that solves your problem.
Update 1: Added a explanation of how this works to the original question where I posted this solution.
Update 2: I've made it Rails 4 compatible with remote: true links and renamed the helper method to js_will_paginate.
Hey if you want to paginate products then try this:
app/controllers/products_controller.rb
def index
@products = Product.paginate(page: params[:page], per_page: 10)
end
views/products/index.html.erb
<div class = "sort_paginate_ajax"><%= render 'products' %></div>
views/products/_products.html.erb
<% @products.each do |product| %>
# your code
<% end %>
<%= will_paginate @products %>
views/products/index.js.erb
$('.sort_paginate_ajax').html("<%= escape_javascript(render("products"))%>")
assets/javascripts/application.js
$(function() {
$(".sort_paginate_ajax th a, .sort_paginate_ajax .pagination a").on("click", function(){
$.getScript(this.href);
return false;
});
});
So first we are calling paginate method on Product for all products, here an offset will be set according to params[:page]
and limit will be set by per_page
options.
Also we are rendering products
partial which will be rendered every time when other page is opened.
In partial call on @products
that you want, and then will_paginate
method is applied on
@products
, it also creates params[:page]
that is used in controller.
Now in response to ajax request render content of div
having class sort_paginate_ajax
with the partial that we created.
Also to make request ajax request, on document load capture script of all a
tags in div.sort_paginate_ajax
, and return false.
Now pages will be called with ajax request
I hope this would help you.
Additional to previous answer.
string of code:
$(".sort_paginate_ajax th a, .sort_paginate_ajax .pagination a").on("click", function(){
replace with string:
$(".sort_paginate_ajax").on("click", ".pagination a", function(){
The onclick event applied only to the elements that already exist. So, for new appears links, need delegate click event from parent ".sort_paginate_ajax" to childs ".pagination a".
You could just use JQuery:
Controller:
def index
@posts = Post.paginate(:page => params[:page])
respond_to do |format|
format.html
format.js
end
end
Then in index.html.erb:
<div id="post-content", posts: @posts >
<%= j render 'post_content' %>
</div>
In partial '_post_content.html.erb':
<%= will_paginate @posts %>
<% @posts.each do |post| %>
<p><%= post.content %></p>
<% end %>
pagination.js:
$(document).ready(function() {
$('.pagination > a').attr('data-remote', 'true');
});
index.js.erb:
$('#post-content').html("<%= j render 'post_content' %>")
Make sure to add the
$('.pagination > a').attr('data-remote', 'true');
again in your JS template (index.js.erb), so it sets the links data-remote again when the Ajax runs.