Подтвердить что ты не робот

Как реализовать ajax pagination с помощью will_paginate gem

Я использую will_paginate gem в моем проекте ROR для отображения записей на страницах.

Я хочу, чтобы следующая страница загружалась без перезагрузки всей страницы с помощью ajax.

Я нашел несколько примеров в сети, но они не работают для меня.

Как это сделать?

4b9b3361

Ответ 1

Создайте новый помощник (например, app/helpers/will_paginate_helper.rb) со следующим содержимым:

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

Затем в вашем представлении используйте этот тег для разбивки ajax:

<%= js_will_paginate @recipes %>

Помните, что ссылки на страницы будут содержать существующие параметры URL-адреса, вы можете исключить их, как показано ниже. Это стандартная функция для разбивки на страницы:

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

Надеюсь, что решает вашу проблему.

Обновление 1: добавлено объяснение того, как это работает с оригинальным вопросом, где я разместил это решение.

Обновление 2. Я сделал его Rails 4 совместимым с remote: true links и переименовал вспомогательный метод в js_will_paginate.

Ответ 2

Эй, если вы хотите разбивать на страницы продукты, попробуйте следующее:

приложение/контроллеры/products_controller.rb

def index
  @products = Product.paginate(page: params[:page], per_page: 10)
end

Виды/продукты/index.html.erb

<div class = "sort_paginate_ajax"><%= render 'products' %></div>

Виды/продукты/_products.html.erb

<% @products.each do |product| %>
# your code
<% end %>
<%= will_paginate @products %>

Виды/продукты/index.js.erb

$('.sort_paginate_ajax').html("<%= escape_javascript(render("products"))%>")

активы/JavaScripts/application.js

$(function() {
  $(".sort_paginate_ajax th a, .sort_paginate_ajax .pagination a").on("click", function(){
    $.getScript(this.href);
    return false;
  });
});

Итак, сначала мы вызываем метод paginate для Product для всех продуктов, здесь смещение будет установлено в соответствии с params[:page], а ограничение будет установлено параметрами per_page. Также мы рендерим products partial, который будет отображаться каждый раз, когда открывается другая страница.

При частичном вызове @products, который вы хотите, и затем применяется метод will_paginate @products, он также создает params[:page], который используется в контроллере.

Теперь в ответ на запрос ajax отобразите содержимое div с классом sort_paginate_ajax с частичным, который мы создали.

Также, чтобы сделать запрос ajax запроса, захватить загрузку документа script всех тегов a в div.sort_paginate_ajax и вернуть false.

Теперь страницы будут вызываться с помощью запроса ajax

Надеюсь, это поможет вам.

Ответ 3

Дополнительно к предыдущему ответу.

строка кода:

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

заменить на строку:

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

Событие onclick применяется только к уже существующим элементам. Таким образом, для новых появившихся ссылок необходимо делегировать событие щелчка от родителя ".sort_paginate_ajax" к childs ".pagination a..

Ответ 4

Вы можете просто использовать JQuery:

Контроллер:

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

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

Затем в index.html.erb:

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

В частичном '_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' %>")

Обязательно добавьте

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

снова в вашем шаблоне JS (index.js.erb), поэтому он снова устанавливает удаленные данные с данными, когда запускается Ajax.

Ответ 5

Чтобы следить за отличным ответом @Pierre на создание помощника, я видел некоторые последующие вопросы относительно обновления представлений (проблема, которую я изначально имел). @Pierre следует этой проблеме, заявив, что вам нужно создать ответ js. Вот что я сделал после создания помощника:

в моем show.html.erb

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

Я создал еще один файл с именем show.js.erb(так что два формата для показа)

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

Ответ 6

Я хочу расширить ответ Пьера.

Если вы используете материализовать sass с will_paginate_materialize, то у вас будет инициализатор для стилизации ссылок на страницы.

gem 'will_paginate', '~> 3.1.0'

gem 'will_paginate-materialize', git: 'https://github.com/mldoscar/will_paginate-materialize', branch: 'master'

Итак, чтобы заставить удаленное true работать с ссылками, отображаемыми инициализатором will_paginate_materialize, я сделал это:

will_paginate_helper.rb

module WillPaginateHelper
  class WillPaginateJSLinkRenderer < WillPaginate::ActionView::LinkRenderer
  end
  def js_will_paginate(collection, options = {})
    will_paginate(collection, options.merge(:renderer =>WillPaginateHelper::WillPaginateJSLinkRenderer))
  end
end

Я изменил инициализатор материализации страницы, чтобы он выглядел так:

will_paginate_materialize.rb

MaterializePagination::MaterializeRenderer.module_eval do
  def page_number(page)
    classes = ['waves-effect', ('active' if page == current_page)].join(' ')
    tag :li, link(page, page, :rel => rel_value(page)), class: classes
  end

  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

WillPaginate::ViewHelpers::LinkRenderer.class_eval do
  def symbolized_update(target, other, blacklist = nil)
    other.each_pair do |key, value|
      key = key.to_sym
      existing = target[key]
      next if blacklist && blacklist.include?(key)

      if value.respond_to?(:each_pair) and (existing.is_a?(Hash) or existing.nil?)
        symbolized_update(existing || (target[key] = {}), value)
      else
        if value.instance_variable_defined?(:@parameters)
          value = value.instance_variable_get(:@parameters)
        end
        target[key] = value
      end
    end
  end
end

На мой взгляд, я оставил рендерер в той же ссылке:

= will_paginate results, renderer: MaterializePagination::Rails