Sunday, July 5, 2009

Ajaxified Will Paginate

I added the will_paginate plug-in for my rails 2.3.2 application but quickly found that there was no way I could ajaxify it. So I made a renderer of my own by modifyind some code. It was fun and effective.

The will_paginate.rb file inside config/initializers look like this..


class PaginationListLinkRenderer < WillPaginate::LinkRenderer

def to_html
links = @options[:page_links] ? windowed_links : []

links.unshift(page_link_or_span(@collection.previous_page, 'previous', @options[:previous_label]))
links.push(page_link_or_span(@collection.next_page, 'next', @options[:next_label]))

html = links.join(@options[:separator])
@options[:container] ? @template.content_tag(:ul, html, html_attributes) : html
end

protected

def windowed_links
visible_page_numbers.map { |n| page_link_or_span(n, (n == current_page ? 'current' : nil)) }
end

def page_link_or_span(page, span_class, text = nil)
text ||= page.to_s
if page && page != current_page
page_link(page, text, :class => span_class)
else
page_span(page, text, :class => span_class)
end
end

def page_link(page, text, attributes = {})
if @options[:ajax].nil?
return @template.content_tag(:li, @template.link_to(text, url_for(page)), attributes)
else
return @template.content_tag(:li, @template.link_to(text,'#', :onclick => ajax_url_for(page)), attributes)
end
end

def ajax_url_for(page)
return @options[:fn_name]+'("'+ (page.to_s) +'")'
end

def page_span(page, text, attributes = {})
@template.content_tag(:li, text, attributes)
end

end

WillPaginate::ViewHelpers.pagination_options[:renderer] = 'PaginationListLinkRenderer'
WillPaginate::ViewHelpers.pagination_options[:previous_label] = 'Prev'
WillPaginate::ViewHelpers.pagination_options[:next_label] = 'Next'


The ajax_url_for page gives the javascript to be called for the link. The options added are


:ajax => true (to signify that it is an Ajax request)
:fn_name => some_function_name (The Javascipt function which has the Ajax call)


The view is a partial which requires these local variables to be passed


A collection of paginated records using will_paginate's Model.paginate(:page => page)
A base_url which has the url to which the page parameter should be added.
The container which should be populated after the Ajax call.


The partial looks like this ...


<script type="text/javascript"><br />var access_page_for_paginate = function(page_no){<br /> <%= remote_function(:update => container, :url => base_url, :with => '"page="+page_no') %><br />}<br /></script>
<div class="pagination_container">
<%= will_paginate collection, :ajax => true, :base => base_url,
:container => container, :fn_name => 'access_page_for_paginate' %>
</div>


And the partial is called like this ..


<%= render :partial => 'partials/ajax_paginate',
:locals => {:collection => @feeds, :base_url => show_service_url, :container => 'profile_all'} %>

No comments: