Search code examples
javascripthtmlcssinfinite-scroll

How to stop infinite scroll from loading on top of page?


When the infinite scroll gets near to the end, it loads back to the top of the page and refreshes.

How do I stop that so it loads new images with previous images, and stop it from loading back at the top and refresh?

I don't want the infinite scroll to be implemented in the favourites section, only the show contents section.

Appreciate any help, thanks.

const resultsNav = document.getElementById('resultsNav');
const favouritesNav = document.getElementById('favouritesNav');
const imagesContainer = document.querySelector('.images-container');
const saveConfirmed = document.querySelector('.save-confirmed');
const loader = document.querySelector('.loader');


// Unsplash API
const count = 10;
const apiKey = 'UNSPLASH_API_KEY';
const apiUrl = `https://api.unsplash.com/photos/random?client_id=${apiKey}&count=${count}`;

let resultsArray = [];
let favourites = {};


function showContent(page) {
  window.scrollTo({ top: 0, behavior: 'instant'});
  if (page === 'results') {
    resultsNav.classList.remove('hidden');
    favouritesNav.classList.add('hidden');
  } else {
    resultsNav.classList.add('hidden');
    favouritesNav.classList.remove('hidden');
  }
  loader.classList.add('hidden');
}

function createDOMNodes(page) {
  const currentArray = page === 'results' ? resultsArray : Object.values(favourites);
  currentArray.forEach((result) => {
    // Card Container
    const card = document.createElement('div');
    card.classList.add('card');
    // link
    const link = document.createElement('a');
    link.href = result.links.html;
    link.target = '_blank';

    //Images
    const image = document.createElement('img');
    image.src = result.urls.regular;
    image.alt = 'Image';
    image.loading = 'lazy';
    image.classList.add('card-img-top');
    //Card Body
    const cardBody = document.createElement('div');
    cardBody.classList.add('card-body');
    // Save Text
    const saveText = document.createElement('p');
    saveText.classList.add('clickable');
  if (page === 'results') {
    saveText.textContent = 'Add To Favourites';
    saveText.setAttribute('onclick', `saveFavourite('${result.urls.regular}')`);
  } else {
    saveText.textContent = 'Remove Favourite';
    saveText.setAttribute('onclick', `removeFavourite('${result.urls.regular}')`);
  }

    // Append
    cardBody.append(saveText);
    link.appendChild(image);
    card.append(link, cardBody);
    imagesContainer.appendChild(card);
  });
}

function updateDOM(page) {
  // Get Favourites from localStorage
  if (localStorage.getItem('unsplashFavourites')) {
    favourites = JSON.parse(localStorage.getItem('unsplashFavourites'));
  }
  imagesContainer.textContent = '';
  createDOMNodes(page);
  showContent(page);
}

//  Get 10 Images from Unsplash API
async function getUnplashPictures() {
// Show loader
loader.classList.remove('hidden');
  try {
    const response = await fetch(apiUrl);
    resultsArray = await response.json();
    updateDOM('results');
  } catch (error) {
    // Catch Error Here
  }
}

// Add result to Favourites
function saveFavourite(itemUrl) {
  // Loop through Reuslts Array to select Favourite
  resultsArray.forEach((item) => {
    if (item.urls.regular.includes(itemUrl) && !favourites[itemUrl]) {
      favourites[itemUrl] =item;
      // Show Save Confirmation for 2 Seconds
      saveConfirmed.hidden = false;
      setTimeout(() => {
        saveConfirmed.hidden = true;
      }, 2000);
      // Set Favourites in localStorage
      localStorage.setItem('unsplashFavourites', JSON.stringify(favourites));
    }
  });
}

// Remove item from Favourites
function removeFavourite(itemUrl) {
  if (favourites[itemUrl]) {
    delete favourites[itemUrl];
    // Set Favourites in localStorage
    localStorage.setItem('unsplashFavourites', JSON.stringify(favourites));
    updateDOM('favourites');
  }
}

// Check to see if scrolling near bottom of page, Load More Photos
window.addEventListener('scroll', () => {
  if (window.innerHeight + window.scrollY >= document.body.offsetHeight - 1000) {
    getUnplashPictures();
  }
});

// On Load
getUnplashPictures();

Solution

  • The problem is in two lines of your code. First, as noted in comments,

    window.scrollTo({ top: 0, behavior: 'instant'});
    

    Is what scrolls the page to the top and you should remove it. Another problem is in the fetch logic:

    resultsArray = await response.json();
    

    Deletes the content of the whole list and replace it with the new records! That means you don't add the new data to the already-fetched records when loading more data, but replace the current data with the new.

    Possible solution:

    const newResultsArray = await response.json();
    resultsArray = resultsArray.concat(newResultsArray); // Combine new and already-fetched records
    

    I changed those two lines in the jsfiddle and tried it with a mock data (the api gives errors). It worked for me.