DEV Community

Cover image for Adding lazy loading of items using htmx
Cristian Molina
Cristian Molina

Posted on

Adding lazy loading of items using htmx

This is a continuation of some testing of these front-end libraries.
I used the lazy load example here to add lazy loading of the articles on this index page.

This is how it looks like:

a spinning animation before showing articles

Previous to this change, I created an Articles Active Record model, ran migrations, and changed the insert action to create new records.

I added a GET htmx definition in the index view code to fetch the items' partial and added a route and a controller action for this new response.

You can see that there is an extra logic in the Articles::IndexView to discern between displaying the lazy load code or the fragment with the list of articles. This is based on an initialization parameter. I'd probably refactor this later, maybe extracting the list block into a new component.

Here is the important code changes:

Route definition

  resources :articles do
    get "items", on: :collection
  end
Enter fullscreen mode Exit fullscreen mode

Controller changes

  def index
    render Articles::IndexView.new(nil)
  end

  def items
    articles = Article.all.order(id: :desc)
    sleep 1 # this is to simulate a slow response and should be removed in a real scenario
    render Articles::IndexView.new(articles), layout: false
  end
Enter fullscreen mode Exit fullscreen mode

Changes in the index view class

class Articles::IndexView < ApplicationView
...
  def template
    if @articles.nil?
      title_with_add_button
      load_indicator_placeholder
    else
      load_articles_section
    end
  end

  def load_indicator_placeholder
    div("hx-get": items_articles_path, "hx-trigger": "load", class: "flex justify-center") {
      img(alt: "Loading items...",
        class: "htmx-indicator", width: "150", src: "/bars.svg")
    }
  end

  def load_articles_section
    section(id: "article-list", class: "grid md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4") {
      articles.each { |el| render el }
    }
  end
Enter fullscreen mode Exit fullscreen mode

Also available in the GitHub repo

Happy hacking!

Top comments (0)