infinite scroll using intersection observer

youtube

by ygongdev

HTML

<ul id="infinite-scroll-list">
  <p id="loader">
    isLoading
  </p>
</ul>

CSS

.item {
  height: 200px;
  background-color: gray;
  margin-bottom: 20px;
  font-size: 24px;
  text-align: center;
}

#loader {
  position: fixed;
  top: 50%;
  left: 50%;
  transform : translate(-50% -50%);
  font-size: 24px;
}

.show {
  display: block;
}

.hide {
  display: none;
}

JavaScript

const fetchPagingAPI = function(paging) {
	// paging.count
  // paging.start
	const newData = new Array(paging.count).fill().map((_, idx) => paging.start + idx);
  return new Promise((resolve) => {
  	setTimeout(() => resolve(newData), 1000);
  });
} //

class InfiniteScroll {
	get infiniteScrollElement() {
  	return document.querySelector(this.infiniteScrollId);
  }
  
  get loaderElement() {
  	return document.querySelector(this.loaderId)
  }
  
	constructor(infiniteScrollId, loaderId, api, { count }) {
  	this.infiniteScrollId = infiniteScrollId;
    this.loaderId = loaderId;
    this.fetchAPI = api;
    this._start = 0;
    this._count = count;
    this._observedElement = undefined;
    
    this._observer = new IntersectionObserver(this._paginateCallback.bind(this));
    
    this._showLoader(true);
    this._paginate().finally(() => {
    	this._showLoader(false);
    });
  }
  
  _paginateCallback(entries, observer) {
    entries.forEach(entry => {
			if (entry.isIntersecting) {
      	// show a loader
        this._showLoader(true);
        this._paginate().finally(() => {
        	this._showLoader(false);
        });
      }
    })
  }
  
  _showLoader(show) {
  	if (show) {
    	this.loaderElement.classList.add('show');
      this.loaderElement.classList.remove('hide');
    } else {
      this.loaderElement.classList.remove('show');
      this.loaderElement.classList.add('hide');
    }
  }
  
  async _paginate() {
  	const paging = {
      start: this._start,
      count: this._count
    }
    
    const data = await this.fetchAPI(paging);
    
    this._start += this._count;
    
    this._addToDOM(data);
  }
  
  _addToDOM(data) {
  	const fragment = document.createDocumentFragment();
    
    if (this._observedElement) {
    	this._observer.unobserve(this._observedElement);
    }
    
    for (let i = 0; i< data.length; i++) {
    	const li = document.createElement('li');
      li.textContent = data[i] + 1;
      li.classList.add('item');
      
    ...