Recipe 6.7
Using Infinite Scroll
Demo
Employees
Loading...
Loading users...
Code
JavaScript
const results = document.querySelector('.users');
/**
* Observes a placeholder element with an IntersectionObserver.
* When the placeholder becomes visible, more data is loaded.
*
* @param placeholder The "Load More" placeholder element
* @param loadMore A function that loads more data
*/
function observeForInfiniteScroll(placeholder, loadMore) {
const observer = new IntersectionObserver(entries => {
// If the placeholder becomes visible, it means the user
// has scrolled to the bottom of the list. In this case, time to
// load more data.
if (entries[0].isIntersecting) {
loadMore();
}
});
observer.observe(placeholder);
}
observeForInfiniteScroll(document.querySelector('.load-more'), loadUsers);
async function loadUsers() {
const response = await fetch('/api/users');
const users = await response.json();
users.forEach(user => {
const userCard = document.querySelector('#user-template').content.cloneNode(true).firstElementChild;
userCard.querySelector('.card-title').textContent = `${user.firstName} ${user.lastName}`;
userCard.querySelector('.job-title').textContent = user.jobTitle;
results.appendChild(userCard);
});
}
HTML
<style>
.container {
height: 30rem;
overflow: auto;
}
</style>
<template id="user-template">
<div class="card my-2">
<div class="card-body">
<h4 class="card-title"></h4>
<div class="job-title"></div>
</div>
</div>
</template>
<div class="container">
<h2>Employees</h2>
<div class="users"></div>
<div class="card my-2 load-more">
<div class="card-body text-center">
<div class="spinner-border" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<div>Loading users...</div>
</div>
</div>
</div>