'Best way to trigger an ajax call for loadining infinite elements?
Problem:
I am writing a website that shows users photos.
By default my api returns a certain number of photos by default (20), I want if the user keeps scrolling for more photos to load and be visible to the user.
Current solution
$(document).ready(function() {
let callAllowed = true;
$(window).scroll(function () {
if ($(window).scrollTop() > $('#images').height() / 2) {
if (callAllowed){
callAllowed = false;
request = $.ajax({
url: '/load',
type: "POST",
data: {}
});
request.done(function(html){
$(html).appendTo('#images');
callAllowed = true;
});
}
});
}
});
So basically I say once the user has scrolled half way down the images, load the new images and append them to the images already there. I use the callAllowed variable to prevent multiple calls being triggered.
Now this works but is not a good solution at all.
The problem is that at the start $(window).scrollTop() > $('#images').height() / 2
loads at an appropriate point but as $('#images').height()
grows it begins making calls that are completely unnecessary for example when I have 20 images on screen it will begin loading the next batch when I am onto 10 left to view, which seems okay however when I have a 100 images loaded it could make the call with 50 images that the user still can scroll through, that is it is making the call before it really needs to. As the user keeps scrolling this problem becomes rather stupid, I don't need to be loading in more images when the user still has 200 images loaded below for them to scroll until!
Possible Improvement
I would like to say instead of $(window).scrollTop() > $('#images').height() / 2
something like:
When I have 10 more images that I have not yet scrolled through make the api call to load the next batch of images.
But I am not sure how to do this.
Can anyone offer some advice?
Solution 1:[1]
Use the Intersection Observer API. This API is created to check wether observed elements are within the viewport, or specified bounds. It will fire a callback whenever a change triggers in one the elements and enables you to act whenever an element moves into our out of the area that you are observing in.
Mind the threshold
property in the settings of the Intersection Observer. The 0.5
value will indicate a trigger whenever 50% or more of an observed element has entered or left the viewport. That would be similar to the $('#images').height() / 2
equation.
const onObserve = entries => {
for (const entry of entries) {
if (entry.isIntersecting) {
entry.target.classList.add('loaded');
// Call your request here.
}
}
};
const observer = new IntersectionObserver(onObserve, {
root: null,
rootMargin: '0px',
threshold: 0.5
});
const images = document.querySelectorAll('.image');
for (const image of images) {
observer.observe(image);
}
body {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 15px;
}
.image {
position: relative;
aspect-ratio: 16 / 9;
background-color: #f7f7f7;
border: 1px solid #d0d0d0;
border-radius: 5px;
transition: background-color 150ms ease-out;
}
.image.loaded {
background-color: red;
}
<div class="image"></div>
<div class="image"></div>
<div class="image"></div>
<div class="image"></div>
<div class="image"></div>
<div class="image"></div>
<div class="image"></div>
<div class="image"></div>
<div class="image"></div>
<div class="image"></div>
<div class="image"></div>
<div class="image"></div>
<div class="image"></div>
<div class="image"></div>
<div class="image"></div>
<div class="image"></div>
<div class="image"></div>
<div class="image"></div>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |