@pagy, @activities = pagy(Activity.order(created_at: :desc).includes(:user, :trackable), limit: 4)
respond_to do |format|
format.html
format.json { render json: { entries: render_to_string(partial: "activities/activity", collection: @activities, formats: [ :html ]), pagination: view_context.pagy_nav(@pagy) } }
end
<section data-controller="infinite-scroll" data-action="scroll@window->infinite-scroll#scroll">
<div class="hidden" data-infinite-scroll-target="pagination">
<%== pagy_nav(@pagy) %>
</div>
<div data-infinite-scroll-target="entries">
<%= render partial: 'activities/activity', collection: @activities %>
</div>
</section>
import { Controller } from "@hotwired/stimulus"
// Connects to data-controller="infinite-scroll"
export default class extends Controller {
static targets = ["entries", "pagination"]
connect() {
this.lastUrl = "";
}
scroll() {
let body = document.body,
html = document.documentElement;
let nextPage = this.paginationTarget.querySelector("[aria-label='Next']")
if (nextPage == null || nextPage.href == "") {
return
}
let height = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight)
if (window.innerHeight + window.scrollY >= height - 100) {
this.loadMore(nextPage.href);
}
}
async loadMore(url) {
if (url === this.lastUrl) {
return
}
this.lastUrl = url;
try {
const response = await fetch(url, {
headers: {
Accept: "application/json"
}
})
if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`)
const data = await response.json()
this.entriesTarget.insertAdjacentHTML("beforeend", data.entries)
this.paginationTarget.innerHTML = data.pagination
} catch (error) {
console.error("Error loading more entries:", error)
}
}
}