【问题标题】:How to Implement ajax pagination with will_paginate gem如何使用 will_paginate gem 实现 ajax 分页
【发布时间】:2012-11-17 10:02:48
【问题描述】:

我在我的ROR 项目中使用will_paginate gem 在页面中显示记录。

我希望在不使用ajax 重新加载整个页面的情况下加载下一页。

我在网上找到了一些例子,但它们对我不起作用。

如何做到这一点?

【问题讨论】:

    标签: ajax ruby-on-rails-3 will-paginate


    【解决方案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:在我发布此解决方案的 original question 中添加了对其工作原理的说明。

    更新 2:我已使其 Rails 4 与 remote: true 链接兼容,并将辅助方法重命名为 js_will_paginate

    【讨论】:

    • 我已经在几个地方看到了你的答案——在实现你的代码之后,控制器肯定会被命中并且结果是从数据库中提取的。但是页面根本没有改变。我错过了什么?服务器日志显示“Rendered jobs/_jobstable.html.erb (80.7ms)”但我屏幕上的实际页面没有呈现。
    • 浏览器正在进行一个 jquery ajax 调用(脚本类型),它期望一个 JS 响应来更新视图。一种响应方法是使用 JS 但是您可以稍微修改代码以执行任何操作想要。
    • 这个 hack 在 Rails 3.x 上就像一个魅力,但在 Rails 4.2 上不再可用。 link_to_function 已弃用。你能把更新吗?提前致谢。
    • 嘿,我正在尝试使用这种方法进行 ajax 分页,在控制台中似乎所有内容都已处理,但最重要的事情没有发生:分页项不会改变!它只是不会改变页面,所以当你点击分页链接时没有任何反应......
    • 您的控制器应该响应 JS 请求并重新呈现页面上的部分。例如,您的 JS 视图文件可以使用 jQuery 响应: $('#items').html('');
    【解决方案2】:

    嘿,如果你想对产品进行分页,那么试试这个:

    app/controllers/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>
    

    views/products/_products.html.erb

    <% @products.each do |product| %>
    # your code
    <% end %>
    <%= will_paginate @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;
      });
    });
    

    所以首先我们为所有产品调用 Product 的 paginate 方法,这里将根据params[:page] 设置偏移量,并通过per_page 选项设置限制。 此外,我们正在渲染 products 部分,每次打开其他页面时都会渲染。

    在你想要的@products的部分调用中,然后应用will_paginate方法 @products,它还创建在控制器中使用的params[:page]

    现在响应 ajax 请求,呈现具有类 sort_paginate_ajaxdiv 的内容以及我们创建的部分内容。

    同样做请求ajax请求,在div.sort_paginate_ajax中所有a标签的文档加载捕获脚本,并返回false。

    现在页面将通过 ajax 请求调用

    希望对你有帮助。

    【讨论】:

    • 很好,我发现的问题是第一次点击页面效果很好,但是在移动到下一页后,ajax 调用不适用于链接,它被称为 html 请求,意味着当进行第一个ajax调用并替换部分时,分页链接中不再附加任何实时事件,因此我将正确的js添加到js.erb文件中以在新的部分时将实时事件绑定到链接将被渲染并且效果很好。 !注意,从 jQuery 1.7 开始不推荐使用 live 方法,因此您必须将其替换为 .on() 而不是 .live()
    • @rmagnum2002 当您说您将正确的 js 添加到 js.erb 文件中时,您能否提供一个示例,我遇到了一个问题,即第一个下一个链接效果很好,但第二个请求会生成一个链接例如在 /?_=1399023289230&amp;page=3 的 url 中。我也将 .live() 更改为 .on(),谢谢
    • @Richlewis youtube.com/watch?v=UbtmSsjKn38 我在我的项目中使用过这个几次.. 不记得我在说什么是正确的 js。可能与 .on() 和 .live() 事件有关。
    【解决方案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”的点击事件委托给子级“.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 %>
      

      分页.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】:

        我想扩展皮埃尔的答案。

        如果您将 materialize sass 与 will_paginate_materialize 一起使用,那么您将有一个初始化器来设置分页链接的样式。

        gem 'will_paginate', '~&gt; 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 初始化器更改为如下所示:

        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

        【讨论】:

          【解决方案6】:

          为了继续 @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 %>');
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2016-09-24
            • 1970-01-01
            • 1970-01-01
            • 2012-11-27
            • 2012-07-18
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多