简体   繁体   中英

Ajax call in rails 3.2.3 with will_paginate gem

Im trying to implement an Ajax call with the will_paginate gem, I found this guide http://ramblinglabs.com/blog/2011/11/rails-3-1-will_paginate-and-ajax which seemed like a simple solution, though it includes coffeescript which i am not familiar with, so if anyone has a different solution then please advise..

My code is as follows

My View

<div class="container">
 <div class="row">
  <div id="userRecipes">
   <%= render partial: 'userrecipes' %>
 </div>
</div><!--/row-->

My partial (userrecipes)

 <% @recipes.each do |r| %>
  <div class="span3">
   <div class="thumbnail">
    <%= image_tag r.avatar.url(:myrecipes) %>
   </div>
   <h4><%= link_to r.dish_name, r %></h4>
   <hr>
    <p><%= truncate r.description, :length => 90 %></p>
    <p><%= link_to "Edit Recipe", edit_recipe_path(r.id) %></p>
    <p><%= link_to "Delete Recipe", recipe_path(r.id), :confirm => "Are you sure?", :method => :delete %></p>
    <p><%= link_to "Add to favorites",  {:controller => 'favourites', :action => 'create', :recipe_id => r.id}, {:method => :post } %></p>
   </div><!--/span3-->
   <% end %>
   <%= will_paginate @recipes %>

updated userrecipes.js.erb file

$('#userRecipes').html('<%= escape_javascript(render partial: 'userrecipes') %>');
$.setAjaxPagination();

Coffeescript

$ ->
$.setAjaxPagination = ->
$('.pagination a').click (event) ->
  event.preventDefault()
  loading = $ '<div id="loading" style="display: none;"><span><img src="/assets/loading.gif" alt="cargando..."/></span></div>'
  $('.other_images').prepend loading
  loading.fadeIn()
  $.ajax type: 'GET', url: $(@).attr('href'), dataType: 'script', success: (-> loading.fadeOut -> loading.remove())
  false

  $.setAjaxPagination()

When i click on the next anchor tag to show the next set of results the page stays as it is and no new content appears

When using the console to see if there are any errors i can see any, the output is

GET http://localhost:3000/my_recipes?page=2&_=1355055997639

Am i missing something here? or is there an issue with my userrecipes.js.erb file because in other Ajax examples i have seen thy are using escape_javascript when rendering the partial?

Edit

Whilst inspecting the response in the console it is also showing that the new recipes to be loaded are being loaded but nothing is happening in the view

Any pointers appreciated

Thanks

Why not try a simpler approach, 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.

Explanation:

Will_paginate allows you to create your own custom renderer . The WillPaginateJSLinkRenderer is such a custom renderer and this class could be defined anywhere, it doesn't have to be defined inside the helper module. The custom renderer extends the standard renderer (LinkRenderer) and redefines only two methods.

The prepare method is overriden to explicitly remove the cache buster parameter since will_paginate creates the page urls with all parameters that were present when rendering the page and we do not want to reuse the cache buster parameter.

The link method is a copy paste from the original LinkRenderer source code but creates a link with remote: true to make it a JS resquest.

Finally the js_will_paginate method is a standard view helper method to call the normal will_paginate view helper method but adds our custom renderer to the options so that it will be used instead of the normal renderer.

Just in case someone is looking for Rails 4 solution. I liked the answer from Pierre Pretorius, but it failed for me on 4.1.1 with "method undefined" for link_to_function on the line:

@template.link_to_function(text.to_s.html_safe, ajax_call, attributes)

I just replaced the line to:

@template.link_to(text.to_s.html_safe, '#', attributes.merge(:onclick => "#{ajax_call} event.preventDefault();"))

I hope it may help someone.

You are not escaping javascripts in your js.erb, it should be the problem.

$('#userRecipes').html('<%= escape_javascript(render partial: 'userrecipes') %>');
$.setAjaxPagination();

The ajax_will_paginate is a superb method, but unfortunately it was messing up the UI of the paginate. I had employed another javascript method for more flexibility. And I call this method on pageRender.

function checkForAjaxPaginate(controller,make_ajax){
    var href = "";
    $(".pagination").find("ul").each(function(){
        $(this).find("li").each(function(){
            $(this).find("a").each(function(){
                href = $(this).attr("href");
                if(href.indexOf(controller+".js") != -1){
                    if(make_ajax){
                        $(this).attr("data-remote","true");
                    }
                    else{
                        $(this).attr("href",href.replace(".js",""));
                    }
                }
            });
        });
    });
}

For more flexibility, you just pass the action name in the "controller" variable and pass true to make_ajax if you want to convert it to ajax. All I am doing is to check if the href link is ".js", and if make_ajax is true, then adding an attr "data-remote=true", which in our ROR app makes it ajax. if make_ajax is not true then am just removing the ".js" so the code does not mess. I hope this helps

Pierre Pretorius' answer is great, but I had to do a little more to make it work for me that wasn't already clear. Maybe this will be helpful to other beginners.

In addition to making that helper and using the js_will_paginate tag I did this:

After moving the content I was trying to paginate into a partial ( _recipes.html.erb in the case above), I also created a show.js.erb file (in this same view alongside the partial) with text similar to this:

$('#recipes').html('<%= escape_javascript(render partial: 'recipes') %>');

Then I had to move the js_will_paginate tag to the partial as well at the bottom (so it would be updated as I paginated through or clicked next/previous). Then I had to wrap the render partial helper in the div id you're targeting in the js file, so in this example:

<div id="recipes">
  <%= render partial: "recipes" %> 
</div>

This may have been very clear to others, but I wasn't sure which steps from the OP had to remain and which were unnecessary. These steps worked for me. You don't need to add respond_to js in the controller as the helper takes care of that or have a coffeescript file.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM