TurboScroll
TurboScroll is a minimalistic gem that provides infinite scrolling for Rails based applications using Turbo.
Why a new gem? Leveraging Turbo we can build a very small and efficient implementation for infinite page scrolling without extra dependencies.
It's made to be independent from your choice of pagination. You can use the next-pageable gem, which is another minimalistic gem for very basic paging leveraging Rails concerns, to just provide the functionality you need for infinite scrolling and avoiding a count query on each page request (Your main page might still do a count query but you won't be repeating them when requesting next page data behind the scenes.)
Underlying it depends on ViewComponent and Slim but these are not forced upon the user.
Usage
Controller
Make sure your index action responds both to html and turbo_stream
@articles = Article.scoped.paginate(params[:page]) # next-pageable
respond_to do |format|
format.html
format.turbo_stream
end
index.html.erb|slim
The simplest is to use the turbo_scroll_auto
helper and
nest inside your initial infinite content. This will wrap the
content with an element with id #infinite that will be
used to append new content to for infinite scrolling.
= turbo_scroll_auto page: @articles.next_page_index
- @articles.each do |article|
= article
Alternatively, in your index page, make sure you have a DOM element with ID infinite
and render inside of it your initial page content.
At the bottom of your page, add the infinite scrolling loader
by calling the turbo_scroll_auto
helper and passing the next page index
if a next page is present.
#infinite
- @articles.each do |article|
= article
= turbo_scroll_auto page: @articles.next_page_index
This gem currently assumes that the page parameter is called page
, so in
your controller make sure you use that parameter for selecting
the records for a given page.
When the loader component becomes visible, it will do 2 things
- append the next page to the #infinite dom id
- update the loader to load the next page (when present)
If you want to use a different ID, you'll have to pass it on in turbo_stream response.
index.turbo_stream.erb|slim
Your turbo_stream response can use the turbo_scroll_auto_stream
helper to
append the next page content and update the current loader with a
loader for the next page.
When using the next-pageable gem the next_page_index is already present on the collection when a next page exists.
= turbo_scroll_auto_stream page: @articles.next_page_index
- @articles.each do |article|
= article
More variant (no auto loading, just simple 'more' loading)
= turbo_scroll_more page: @articles.next_page_index
= render(Articles::Row.with_collection(@articles))
Your turbo_stream response can use the turbo_scroll_more_stream
helper to
append the next page content and update the current more loader with a
more loader for the next page.
articles\index.turbo_stream.slim
= turbo_scroll_more_stream page: @articles.next_page_index
= render Articles::Row.with_collection(@articles)
An HTML table alternative for table layouts using CSS grids
As HTML is pretty picky on the tags allowed inside 'table', 'tr', 'td', etc you can consider using CSS grid as an alternative.
.article.row {
display: grid;
grid-template-columns: minmax(0, 2fr) minmax(0, 2fr) minmax(0, 8fr) minmax(0, 2fr) minmax(0, 1fr) 3em;
max-width: 100%;
width: 100%;
}
.article.row .col {
height: 2.75rem;
display: flex;
align-items: center;
width: 100%;
padding-left: 0.5rem;
padding-right: 0.5rem;
}
.article.row .col-head {
font-weight: bolder;
}
.article.row .col-filter {
padding-left: 0rem;
padding-right: 0rem;
}
.article.row .align-right {
justify-content: right;
}
.article.row.striped:nth-child(2n+1) {
background-color: #EEEEEE;
}
which would go hand in hand with this partial for a record row
.article.row.striped
.col = article.articlenumber
.col = article.barcode
.col = article.description
.col = article.supplier
.col.align-right = article.price.print
.col.align-right
a.btn.btn-sm.btn-secondary href=edit_article_path(article)
i.bi.bi-pencil
Using a different DOM ID
In case you want or need to use a different DOM ID you
can pass it on as an extra param to the turbo_scroll_auto_stream
helper.
The below example illustrates this for the case where your
DOM ID is #scroll
.
index.html.slim
= turbo_scroll_auto page: @articles.next_page_index, id: :scroll
- @articles.each do |article|
= article
index.turbo_stream.slim
= turbo_scroll_auto_stream page: @articles.next_page_index, infinite_dom_id: :scroll
- @articles.each do |article|
= article
Installation
Install the gem and add to the application's Gemfile by executing:
$ bundle add turbo-scroll
If bundler is not being used to manage dependencies, install the gem by executing:
$ gem install turbo-scroll
License
The gem is available as open source under the terms of the MIT License.