JAVASCRIPT
Implement Infinite Scroll Pagination for API Data
Create a seamless user experience by implementing infinite scroll pagination using JavaScript's Fetch API and Intersection Observer to load more data as users scroll.
// index.html
/*
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Infinite Scroll API Pagination</title>
<style>
body { font-family: sans-serif; margin: 20px; }
.item { border: 1px solid #eee; padding: 10px; margin-bottom: 10px; }
.loading { text-align: center; padding: 20px; font-style: italic; color: #888; }
</style>
</head>
<body>
<h1>Posts</h1>
<div id="posts-container"></div>
<div id="loading" class="loading">Loading more posts...</div>
<script src="app.js"></script>
</body>
</html>
*/
// app.js
let currentPage = 1;
const postsPerPage = 10;
const postsContainer = document.getElementById('posts-container');
const loadingIndicator = document.getElementById('loading');
let isLoading = false;
let hasMore = true; // Assume there's more data initially
// Function to fetch posts from a dummy API
async function fetchPosts(page) {
isLoading = true;
loadingIndicator.style.display = 'block';
try {
// Using JSONPlaceholder for dummy data
const response = await fetch(`https://jsonplaceholder.typicode.com/posts?_page=${page}&_limit=${postsPerPage}`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const posts = await response.json();
if (posts.length === 0 || posts.length < postsPerPage) {
hasMore = false; // No more data to load
}
posts.forEach(post => {
const postElement = document.createElement('div');
postElement.classList.add('item');
postElement.innerHTML = `
<h3>${post.title}</h3>
<p>${post.body}</p>
<small>Post ID: ${post.id}</small>
`;
postsContainer.appendChild(postElement);
});
currentPage++;
} catch (error) {
console.error('Error fetching posts:', error);
loadingIndicator.textContent = 'Failed to load posts.';
} finally {
isLoading = false;
if (!hasMore) {
loadingIndicator.textContent = 'No more posts to load.';
} else {
loadingIndicator.style.display = 'none';
}
}
}
// Set up Intersection Observer
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
// If the loading indicator is visible and we're not already loading and there's more data
if (entry.isIntersecting && !isLoading && hasMore) {
fetchPosts(currentPage);
}
});
}, {
root: null, // observe against the viewport
rootMargin: '0px', // no margin
threshold: 1.0 // trigger when 100% of the target is visible
});
// Start observing the loading indicator element
observer.observe(loadingIndicator);
// Initial load (optional, or let observer handle it on first scroll)
// fetchPosts(currentPage);
How it works: This JavaScript snippet implements an infinite scroll pagination pattern. It uses the Fetch API to retrieve data from a paginated API and the `IntersectionObserver` API to detect when the user scrolls near the bottom of the page. When the `loadingIndicator` element comes into view, the `fetchPosts` function is triggered to load the next set of data. This provides a smooth, continuous loading experience without requiring users to click "next page" buttons. `isLoading` and `hasMore` flags prevent redundant fetches and indicate when all data has been loaded.