web-dev-qa-db-fra.com

Comment implémenter la pagination ajax avec will_paginate gem

J'utilise will_paginate gem dans mon projet ROR pour afficher les enregistrements dans des pages.

Je veux que la page suivante soit chargée sans recharger toute la page en utilisant ajax.

J'ai trouvé des exemples sur le net mais ils ne fonctionnent pas pour moi.

Comment faire ça?

19

Créez un nouvel assistant (par exemple, app/helpers/will_paginate_helper.rb) avec le contenu suivant:

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

Dans votre vue, utilisez ensuite cette balise pour la pagination ajax:

<%= js_will_paginate @recipes %>

N'oubliez pas que les liens de pagination incluront les paramètres existants de l'URL, vous pouvez les exclure comme indiqué ci-dessous. Ceci est la fonctionnalité standard paginer:

<%= js_will_paginate @recipes, :params => { :my_excluded_param => nil } %>

J'espère que cela résoudra votre problème.

Mise à jour 1 : Ajout d'une explication de la manière dont cela fonctionne à la question d'origine où j'ai posté cette solution.

Update 2 : Je l'ai rendu compatible avec Rails 4 avec remote: true et renommé la méthode d'assistance en js_will_paginate .

31
Pierre Pretorius

Hé, si vous voulez paginer les produits, essayez ceci:

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;
  });
});

Nous appelons donc d'abord la méthode paginate sur Product pour tous les produits. Ici, un décalage sera défini en fonction de params[:page] et la limite en fonction de per_page options. Nous rendons également products partial qui sera rendu à chaque fois que d'autres la page est ouverte.

Dans l'appel partiel sur @products souhaité, puis la méthode will_paginate est appliquée sur @products, elle crée également params[:page] qui est utilisé dans le contrôleur. 

Maintenant, en réponse à la demande ajax, le contenu de div est affiché avec la classe sort_paginate_ajax avec le partiel que nous avons créé. 

Également faire une requête ajax, sur le script de capture de chargement de document de toutes les balises a dans div.sort_paginate_ajax, et renvoyer false.

Maintenant les pages seront appelées avec une requête ajax

J'espère que cela vous aiderait.

17
Akshay Vishnoi

Complément à la réponse précédente.

chaîne de code: 

$(".sort_paginate_ajax th a, .sort_paginate_ajax .pagination a").on("click", function(){

remplacer par de la ficelle:

$(".sort_paginate_ajax").on("click", ".pagination a", function(){

L'événement onclick ne s'appliquait qu'aux éléments déjà existants. Ainsi, pour les nouveaux liens apparaissant, il faut un événement de délégation de clic du parent ".sort_paginate_ajax" à l'enfant ".pagination a".

4
sadnix

Vous pouvez simplement utiliser JQuery:

Manette:

def index
  @posts = Post.paginate(:page => params[:page])      

  respond_to do |format|
    format.html
    format.js
  end
end

Puis dans index.html.erb:

<div id="post-content", posts: @posts >
  <%= j render 'post_content' %>
</div>

Dans '_post_content.html.erb' partiel:

<%= 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' %>")

Assurez-vous d'ajouter le 

$('.pagination > a').attr('data-remote', 'true');

à nouveau dans votre modèle JS (index.js.erb), de sorte qu'il rétablisse les liens data-remote lors de l'exécution d'Ajax.

1
A. Saloff

Pour faire suite à l’excellente réponse de @ Pierre concernant la création d’une aide, j’ai vu quelques questions complémentaires concernant la mise à jour des vues (un problème que j’avais eu au début). @Pierre poursuit avec ce problème en déclarant que vous devez créer une réponse js. Voici ce que j'ai fait après avoir créé l'aide:

dans mon show.html.erb

<div id="see-comments">
    <%= render @comments %>
</div>
<div id="pagination-comments">
    <%= js_will_paginate @comments %>
</div>

J'ai créé un autre fichier appelé show.js.erb (donc deux formats pour show)

// to update comments    
$("#see-comments").html("<%= j render @comments %>");
// to update the pagination links
$("#pagination-comments").html('<%= js_will_paginate @comments %>');
0
eaton9000