Turbolinks Infinite Scroll

Enviornment
Rails 6
Turbolinks
Kaminari
JQuery

class ProductsController < ApplicationController
  def index
    @products = Product.order(:name).page(params[:page])
  end
end

Products table with pagination

<table class="table table-bordered table-sm infinite-scroll">
  <thead>
    <tr>
      <th>Name</th>
      <th>UPC</th>
      <th>Price</th>
    </tr>
  </thead>
  <tbody>
    <% @products.each do |product| %>
      <tr>
        <td>
          <%= product.name %>
        </td>
        <td>
          <%= product.upc %>
        </td>
        <td>
          <%= product.retail_price.format %>
        </td>
      </tr>
    <% end %>
  </tbody>
</table>

<%= page_entries_info @products %>
<%= paginate @products %>

Wrapping the contents of #page_entries_info inside a CSS class

module ApplicationHelper
  def page_entries_info(*)
    tag.span(class: 'page-entries-info') { super }
  end
end

infinite-scroll.js

initInfiniteScroll = ->
  $table = $('.infinite-scroll')
  return if $table.length == 0

  # Flag for request status
  loading = false
  
  # Hide the pagination
  $('.page-entries-info, .pagination').hide()
  
  # Add loading message to the bottom of the table
  $table.after('<div class="alert alert-light text-center loading">LOADING...</div>')

  handleScroll = ->
    return if loading

    # if next page link exists
    if url = $('.pagination .page-link[rel=next]').attr('href')
      if $(window).scrollTop() > $(document).height() - $(window).height() - 500
        loading = true

        ajax(url, {
          headers:
            # To get HTML response
            'Accept' : 'text/html, application/xhtml+xml'
        }).then((r) => r.text()).then (html) ->
          $html = $('<html />').append(html)
          # Append new records to the table
          $table.find('tbody').append $html.find('tbody tr')
          # Update pagination
          $('.pagination').html $html.find('.pagination')

          loading = false

    else # no more pages to load
      $(window).off('scroll', handleScroll)
      $('.loading').remove()
      $('.page-entries-info').show()

      # show a message, when all the records are loaded
      if $('.pagination').length > 0
        pageTitle = document.getElementsByClassName('page-title')[0].innerText.toLowerCase()
        totalRecords = $('.page-entries-info b:last').text()
        $('.page-entries-info').html "Displaying <b>all #{totalRecords}</b> #{pageTitle}"

  $(window).on('scroll', handleScroll)
  handleScroll()

window.addEventListener 'turbolinks:load', ->
  initInfiniteScroll()

# To prevent multiple scroll events on turbolinks:load
document.addEventListener 'turbolinks:before-render', ->
  $(window).off('scroll')

🙂

Leave a Reply

Your email address will not be published. Required fields are marked *