Home > Back-end >  To make a Constructor Asynchronous and only be called once all the data from the API is retrieved in
To make a Constructor Asynchronous and only be called once all the data from the API is retrieved in

Time:12-17

Data fetched from the API stored in the Array : movieInfo

let movieInfo = [];

async function popularMovies() {
  let page = 1;

  let lastResult = [];

  do {
    try {
      const resp = await fetch(popularAPIURL   `&page=${page}`);
      const data = await resp.json();
      lastResult = data.total_pages;
      data.results.forEach((result) => {
        movieInfo.push(result);
      });
      page  ;
    } catch (err) {
      console.error(`Oops, Something is wrong ${err}`);
    }
  } while (lastResult);

  console.log(movieInfo);
}

console.time("Time my API Call");
popularMovies();
console.timeEnd("Time my API Call");

Constructor function created for HTML pagination which also renders data from the Array: movieInfo to create respective Movie cards which basically displays the movie name, image and descp. Now I want to make this Constructor Asynchronous and only be called once the Array : MovieInfo has retrieved all the data from the API

class Paginator {
  constructor(totalRecords, recordsPerPage = 1, visiblePages = 1) {
    this.recordsPerPage = recordsPerPage;
    this.totalRecords = totalRecords;
    this.noOfPages = Math.ceil(this.totalRecords / this.recordsPerPage);
    this.visiblePages = visiblePages;
    this.activePage = 1;
    this.visiblePagesEndRange = visiblePages;

    this.validate();
  }

  validate() {
    if (this.recordsPerPage <= 0) {
      this.recordsPerPage = 1;
    }
    if (this.visiblePages <= 0) {
      this.visiblePages = 1;
    }
    if (this.totalRecords <= 0) {
      this.totalRecords = 1;
    }
    if (this.noOfPages <= 0) {
      this.noOfPages = Math.ceil(this.totalRecords / this.recordsPerPage);
    }
    if (this.visiblePagesEndRange <= 0) {
      this.visiblePagesEndRange = this.visiblePages;
    }
    if (this.visiblePages > this.noOfPages) {
      this.visiblePages = this.noOfPages;
      this.visiblePagesEndRange = this.visiblePages;
    }
    if (this.recordsPerPage > this.totalRecords) {
      this.recordsPerPage = this.totalRecords;
    }
  }

  gotoNextPage() {
    if (this.activePage < this.noOfPages) {
      this.activePage  = 1;

      if (this.activePage > this.visiblePagesEndRange) {
        this.visiblePagesEndRange  = this.visiblePages;
        this.visiblePagesEndRange = Math.min(
          this.visiblePagesEndRange,
          this.noOfPages
        );
      }
    }
  }

  gotoPrevPage() {
    if (this.activePage > 1) {
      this.activePage -= 1;
      if (this.activePage % this.visiblePages === 0) {
        this.visiblePagesEndRange = this.activePage;
      }
    }
  }

  gotoFirstPage() {
    this.activePage = 1;
    this.visiblePagesEndRange = this.visiblePages;
  }

  gotoLastPage() {
    this.activePage = this.noOfPages;
    this.visiblePagesEndRange = this.noOfPages;
  }

  gotoPage(page) {
    this.activePage = page;
  }

  getVisiblePagesRange() {
    let beginningVisiblePage;
    let endingVisiblePage;
    //  When the visiblepagesendrange % visiblepages is not zero (which means that all the pages cannot be fit in the visible pages range) and if our ending page range is equal to total no pages then the beginning would be equivalent to visble page range - ((visible page range mod visiblepage range) - 1) i.e the leftover pages until the end.
    if (
      this.visiblePagesEndRange % this.visiblePages !== 0 &&
      this.visiblePagesEndRange === this.noOfPages
    ) {
      beginningVisiblePage =
        this.visiblePagesEndRange -
        ((this.visiblePagesEndRange % this.visiblePages) - 1);
    }
    // else we are always in a place where, current visible page end range - visible page range   1 will return us the correct beginning position for the page range.
    else {
      beginningVisiblePage = this.visiblePagesEndRange - this.visiblePages   1;
    }
    //Also endingActivePage would be simply equal visiblePagesEndRange.
    endingVisiblePage = this.visiblePagesEndRange;
    return {
      beginningVisiblePage,
      endingVisiblePage,
    };
  }

  getActivePageIndices() {
    // the beginning page index will be current active page multiplied by no of records.
    let beginningPageIndex = (this.activePage - 1) * this.recordsPerPage;
    // the ending page index will be minimum of total records and (beginning   records allowed per page);
    let endingPageIndex = Math.min(
      beginningPageIndex   this.recordsPerPage,
      this.totalRecords
    );
    return { beginningPageIndex, endingPageIndex };
  }
}

// All the render and using Paginator class logic comes here
(function () {
  function nextPage() {
    paginator.gotoNextPage();
    render();
  }

  function prevPage() {
    paginator.gotoPrevPage();
    render();
  }

  function lastPage() {
    paginator.gotoLastPage();
    render();
  }

  function firstPage() {
    paginator.gotoFirstPage();
    render();
  }

  // Delegating event to the parent ul.
  function gotoPage(event) {
    if (event.target.nodeName === "BUTTON") {
      const page = parseInt(event.target.dataset.item);
      paginator.gotoPage(page);
      render();
    }
  }

  const paginationPages = document.querySelector(".pagination__pages");

  paginationPages.addEventListener("click", gotoPage);

  //  paginator object
  // list which is of length 346
  // recordsPerPage = 6
  // visiblePages = 6

  const paginator = new Paginator(movieInfo.length, 20, 6);

  // Method to render the pagination buttons;
  function renderPages() {
    const paginationPages = document.querySelector(".pagination__pages");
    let html = "";
    let { beginningVisiblePage, endingVisiblePage } =
      paginator.getVisiblePagesRange();
    for (let page = beginningVisiblePage; page <= endingVisiblePage; page  ) {
      const pageClass =
        paginator.activePage === page
          ? "pagination__page-btn--active"
          : "pagination__page-btn";
      html  = `<li class='pagination__page'>
   <button data-item=${page} class=${pageClass}>${page}</button>
     </li>`;
    }
    paginationPages.innerHTML = html;
  }

  // Method to render the list items
  function renderList() {
    // const list = document.querySelector(".list");
    const mainContent = document.getElementById("main-content");
    const { beginningPageIndex, endingPageIndex } =
      paginator.getActivePageIndices();
    let html = "";
    for (let index = beginningPageIndex; index < endingPageIndex; index  ) {
      // html  = `<li class='list__item'>${records[index]}</li>`;
      html = `<div >
      <div >
        <figure >
          <img src= "${IMG_URL   movieInfo[index].poster_path}"/>
          <figcaption >
            <h2 >${movieInfo[index].name}</h2>
            <p >${movieInfo[index].overview}</p>
            <a href="" >Read more</a>
          </figcaption>
        </figure>
      </div>
    </div>`;
    }
    mainContent.innerHTML  = html;
  }

  // Main render function
  function render() {
    renderPages();
    renderList();
  }

  render();

  this.firstPage = firstPage;
  this.lastPage = lastPage;
  this.nextPage = nextPage;
  this.prevPage = prevPage;
  this.gotoPage = gotoPage;
})();

CodePudding user response:

Make your IIFE a named function declaration (init() below). And execute that function as a callback for your async Promise resolution.

NOTE: you should surround your call to your async function with a try/catch block.

async function popularMovies() {
  //...
  return movieInfo;
}

popularMovies().then(init);

// Replace your IIFE with this
function init(movieInfo) {
  //...
  const paginator = new Paginator(movieInfo.length, 20, 6);
  //...
}
  • Related