Reputation: 13
Trying to follow this tutorial on creating a infinite scroll with stimulus in rails. Here is what my view looks like :
<div data-controller="feed" data-action="scroll@window->feed#scroll" >
<div data-feed-target="entries">
<%= render(partial: "feed_posts")%>
</div>
<div data-feed-target="pagination" hidden>
<%== pagy_nav(@pagy)%>
</div>
</div>
my rails controller:
def feed
@new_post = Post.new
@pagy, @posts = pagy(Post.where(user_id: current_user.all_following.pluck(:id)).or(Post.where(user_id: current_user.id)).order(created_at: :DESC), items: 5)
respond_to do |format|
format.html
format.json{
render json:{entries: render_to_string(partial: "feed_posts", formats: [:html]), pagination: view_context.pagy_nav(@pagy)}
}
end
end
and finally my js controller:
export default class extends Controller {
static targets = ["entries","pagination"]
scroll(){
let next_page = this.paginationTarget.querySelector("a[rel ='next']")
if(next_page == null ){ return }
let url = next_page.href
var body = document.body,
html = document.documentElement
var height = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight)
if(window.pageYOffset >= height - window.innerHeight - 100){
console.log("loading")
this.loadMore(url)
}
}
loadMore(url){
Rails.ajax({
type: 'Get',
url: url,
dataType: 'json',
success: (data) => {
console.log(data)
this.entriesTarget.insertAdjacentHTML('beforeend', data.entries);
this.paginationTarget.innerHTML = data.pagination
}
})
}
}`
The code in charge for finding out if the bottom of the page is hit runs different amounts of times each time and adds too many results to the view.
How can i make it run once hopefully or have it check to see if the html being added, was added before or not..or maybe that's not a good idea.
Upvotes: 1
Views: 368
Reputation: 434
The source for the tutorial you are using, GoRails, has a follow-up episode called Throttling Infinite Scroll Events in Javascript. If you are not a Pro member of that site, you will not be able to see the video, but there is a link to the source code on GitHub, which is freely available. It provides the following updated infinite_scroll_container.js
:
import { Controller } from "stimulus"
export default class extends Controller {
static targets = ["entries", "pagination"]
scroll() {
let next_page = this.paginationTarget.querySelector("a[rel='next']")
if (next_page == null) { return }
let url = next_page.href
var body = document.body,
html = document.documentElement
var height = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight)
if (window.pageYOffset >= height - window.innerHeight) {
this.loadMore(url)
}
}
loadMore(url) {
if (this.loading) { return }
this.loading = true
Rails.ajax({
type: 'GET',
url: url,
dataType: 'json',
success: (data) => {
this.entriesTarget.insertAdjacentHTML('beforeend', data.entries)
this.paginationTarget.innerHTML = data.pagination
this.loading = false
}
})
}
}
Upvotes: 1
Reputation: 3282
The technique for this called Throttle
: Guarantee the execution of the function regularly, only once every X milliseconds.
Check out details on CSS-TRICKS - Debouncing and Throttling Explained Through Examples
The simple way to use throttle with stimulus is using _throttle
function from lodash
_.throttle(func, [wait=0], [options={}])
Check out use case on Debounce and throttle in Stimulus, _.throttle inside a controller
Upvotes: 1