2

I am working on a pure JavaScript infinite scroll. I have a 4 list of posts.

I am trying to load more posts (clones of the "original" ones) when I reach the bottom of the container.

class InfiniteScroll {
  constructor() {
    this.observer = null;
    this.isLoading = false;
    this.postsContainer = document.querySelector('#postsContainer');
    this.postsArary = postsContainer.querySelectorAll('.post');
    this.iterationCount = Number(this.postsContainer.dataset.currentPage);
    this.perPage = 5;
    this.maxCount = this.postsContainer?.dataset?.maxCount;
    this.numberOfPages = Math.ceil(this.maxCount / this.perPage);
    this.hasNextPage = this.iterationCount < this.numberOfPages;
  }

  loadMorePosts() {
    if (this.hasNextPage) {
      this.postsArary.forEach(item => {
        let postClone = item.cloneNode(true);
        this.postsContainer.appendChild(postClone);
      });
    } else {
      if (this.observer) this.observer.disconnect();
    }
  }

  getLastPost() {
    const allPosts = [...this.postsArary];
    return allPosts[allPosts.length - 1];
  }

  counter() {
     console.log(this.iterationCount);
    if (this.hasNextPage) {
      this.iterationCount++;
      this.postsContainer.dataset.currentPage = this.iterationCount;
    }

    this.postsContainer.dataset.hasNextPage = this.hasNextPage;
    this.hasNextPage = this.iterationCount < this.numberOfPages;
  }

  bindLoadMoreObserver() {
    if (this.postsContainer) {
      this.observer = new IntersectionObserver((entries, observer) => {
        entries.forEach(entry => {
          if (entry && entry.isIntersecting) {
            observer.unobserve(entry.target);
            this.counter();
            this.loadMorePosts();
            observer.observe(this.getLastPost());
          }
        });
      });

      this.observer.observe(this.getLastPost());
    }
  }

  init() {
    this.bindLoadMoreObserver();
  }
}

const infiniteScroll = new InfiniteScroll();
infiniteScroll.init();
body, body * {
  margin: 0;
  padding: 0;
}

body {
  font-family: Arial, Helvetica, sans-serif;
}

.post {
  margin: 20px;
  padding: 15px;
  border: 1px solid #ccc;
  border-radius: 5px;
}

p {
  line-height: 1.5;
}
<div id="postsContainer" data-has-next-page="true" data-current-page="1" data-max-count="11">
  <div class="post">
    <h2>Title 1</h2>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Neque dolorum consequatur nostrum sapiente ipsa! Veniam, laudantium accusantium, odio maxime quo adipisci possimus enim quam, voluptate quidem animi perferendis delectus aliquam?</p>
  </div>
  <div class="post">
    <h2>Title 2</h2>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Neque dolorum consequatur nostrum sapiente ipsa! Veniam, laudantium accusantium, odio maxime quo adipisci possimus enim quam, voluptate quidem animi perferendis delectus aliquam?</p>
  </div>
  <div class="post">
    <h2>Title 3</h2>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Neque dolorum consequatur nostrum sapiente ipsa! Veniam, laudantium accusantium, odio maxime quo adipisci possimus enim quam, voluptate quidem animi perferendis delectus aliquam?</p>
  </div>
  <div class="post">
    <h2>Title 4</h2>
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Neque dolorum consequatur nostrum sapiente ipsa! Veniam, laudantium accusantium, odio maxime quo adipisci possimus enim quam, voluptate quidem animi perferendis delectus aliquam?</p>
  </div>
</div>

The problem

There is an issue with the iterationCount variable: it does not seem to reach the value 2.

I have not been able to spot the cause of that.

What am I doing wrong?

1 Answer 1

2

The array postsArary is initialized in the constructor and never updated: getLastPost() always returns the fourth post instead of the last one that was added dynamically. Consequently, the IntersectionObserver callback is only triggered by the fourth post and not by the one on the bottom of the page.

The updated getLastPost() method:

getLastPost() {
  const allPosts = postsContainer.querySelectorAll('.post');
  return allPosts[allPosts.length - 1];
}

This doesn't completely fix the issue. The third page still won't load because counter() is called before loadMorePosts(). So for the final page, hasNextPage is already false when loadMorePosts() should still load more posts.

The updated callback:

bindLoadMoreObserver() {
    if (this.postsContainer) {
      this.observer = new IntersectionObserver((entries, observer) => {
        entries.forEach(entry => {
          if (entry && entry.isIntersecting) {
            observer.unobserve(entry.target);
            this.loadMorePosts();
            this.counter();
            if (this.hasNextPage) {
              observer.observe(this.getLastPost());
            }
          }
        });
      });

      this.observer.observe(this.getLastPost());
    }
  }
Sign up to request clarification or add additional context in comments.

2 Comments

How would you make it instead?
I updated my answer with specific changes.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.