Module: PagyInfiniteScroll::ViewHelper

Defined in:
lib/pagy_infinite_scroll/view_helper.rb

Instance Method Summary collapse

Instance Method Details

#infinite_scroll_container(pagy, url, options = {}) { ... } ⇒ Object

Renders an infinite scroll container

Examples:

<%= infinite_scroll_container(@pagy, products_path(format: :json)) do %>
  <div data-infinite-scroll-target="itemsContainer">
    <%= render @products %>
  </div>
<% end %>

Parameters:

  • pagy (Pagy)

    The pagy object

  • url (String)

    The URL to fetch more items

  • options (Hash) (defaults to: {})

    HTML and Stimulus options

Options Hash (options):

  • :container_class (String)

    CSS classes for the container

  • :max_height (String)

    Maximum height (e.g., "600px")

  • :data (Hash)

    Additional data attributes

Yields:

  • The content to render inside the container



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/pagy_infinite_scroll/view_helper.rb', line 22

def infinite_scroll_container(pagy, url, options = {}, &block)
  container_class = options[:container_class] || ''
  max_height = options[:max_height] || '600px'
  data_attrs = options[:data] || {}

   :div,
              class: container_class,
              style: "max-height: #{max_height}; overflow-y: auto;",
              data: {
                controller: 'pagy-infinite-scroll',
                pagy_infinite_scroll_url_value: url,
                pagy_infinite_scroll_page_value: pagy.page,
                pagy_infinite_scroll_loading_value: false,
                pagy_infinite_scroll_has_more_value: pagy.next.present?,
                pagy_infinite_scroll_render_mode_value: PagyInfiniteScroll.config.render_mode,
                **stimulus_data_attributes(data_attrs)
              } do
    block.call
  end
end

#infinite_scroll_items_container(options = {}) { ... } ⇒ Object

Renders a scroll target container for items

Examples:

<%= infinite_scroll_items_container do %>
  <%= render @products %>
<% end %>

With table rows

<%= infinite_scroll_items_container(tag: 'tbody') do %>
  <%= render @items %>
<% end %>

Parameters:

  • options (Hash) (defaults to: {})

    HTML options

Options Hash (options):

  • :class (String)

    CSS classes

  • :tag (String)

    HTML tag (default: 'div')

Yields:

  • The content to render inside the container



86
87
88
89
90
91
92
93
94
95
# File 'lib/pagy_infinite_scroll/view_helper.rb', line 86

def infinite_scroll_items_container(options = {}, &block)
  tag = options.delete(:tag) || 'div'
  css_class = options.delete(:class) || ''

   tag,
              class: css_class,
              data: { pagy_infinite_scroll_target: 'itemsContainer' } do
    block.call
  end
end

#infinite_scroll_loading_indicator(options = {}) ⇒ Object

Renders the loading indicator

Examples:

<%= infinite_scroll_loading_indicator %>

Custom text

<%= infinite_scroll_loading_indicator(text: "Loading products...") %>

Parameters:

  • options (Hash) (defaults to: {})

    Options for the loading indicator

Options Hash (options):

  • :text (String)

    Loading text

  • :class (String)

    CSS classes



55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/pagy_infinite_scroll/view_helper.rb', line 55

def infinite_scroll_loading_indicator(options = {})
  text = options[:text] || 'Loading more items...'
  css_class = options[:class] || 'hidden p-4 text-center'

   :div,
              class: css_class,
              data: { pagy_infinite_scroll_target: 'loadingIndicator' } do
     :div, class: 'inline-flex items-center gap-2 text-gray-600' do
      concat(spinner_svg)
      concat((:span, text))
    end
  end
end

#pagy_infinite_scroll_append(container_selector, pagy, records, options = {}) ⇒ Object

Server-side rendering helper for .js.erb templates This provides a simpler alternative to the JSON API approach

Examples:

Simple usage (auto-detects partial from collection)

<%= pagy_infinite_scroll_append "#products", @pagy, @products %>

With explicit partial

<%= pagy_infinite_scroll_append "#products", @pagy, @products, partial: "products/card" %>

With locals

<%= pagy_infinite_scroll_append "#items", @pagy, @items, partial: "items/row", locals: { show_actions: true } %>

Parameters:

  • container_selector (String)

    jQuery/CSS selector for the container

  • pagy (Pagy)

    The pagy object

  • records (ActiveRecord::Relation, Array)

    Records or render options

  • options (Hash) (defaults to: {})

    Rendering options

Options Hash (options):

  • :partial (String)

    Partial path (if not using collection inference)

  • :locals (Hash)

    Additional local variables for the partial



116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/pagy_infinite_scroll/view_helper.rb', line 116

def pagy_infinite_scroll_append(container_selector, pagy, records, options = {})
  # Render the HTML for the records
  html = if options[:partial]
           render partial: options[:partial], collection: records, locals: options[:locals] || {}
         else
           render records
         end

  # Escape the HTML for JavaScript
  escaped_html = escape_javascript(html)

  # Generate JavaScript to append items and update pagination state
  javascript = <<~JS
    (function() {
      var container = document.querySelector('#{container_selector}');
      if (container) {
        container.insertAdjacentHTML('beforeend', '#{escaped_html}');

        // Dispatch event for custom handling
        var event = new CustomEvent('pagy-infinite-scroll:appended', {
          detail: {
            page: #{pagy.page},
            hasMore: #{pagy.next.present?},
            count: #{records.size}
          }
        });
        document.dispatchEvent(event);

        // Update controller values if using Stimulus controller
        var scrollContainer = container.closest('[data-controller~="pagy-infinite-scroll"]');
        if (scrollContainer && scrollContainer.pagyInfiniteScroll) {
          scrollContainer.pagyInfiniteScroll.pageValue = #{pagy.page};
          scrollContainer.pagyInfiniteScroll.hasMoreValue = #{pagy.next.present?};
          scrollContainer.pagyInfiniteScroll.loadingValue = false;
        }
      }
    })();
  JS

  javascript.html_safe
end