Fetching data from Firebase cloud database and showing them with load more button (Pagination) Javascript

Viewed 110

I have tried with this approach but getting Uncaught FirebaseError: Function Query.startAfter() requires a valid first argument, but it was undefined. The lastVisible is getting the value on console. Here is the code:

function loadMoreButtonAction() {
  fetchRequest(true);
}

function fetchRequest(isFromLoadMore) {
    var table = document.getElementById("outputTableID");

  var lastVisible;
  var tableIndex;
  if (isFromLoadMore == false) {
    if (table.rows.length > 2) {
        resetTable(table);
    }

    var first = firestore.collection(parentNode).orderBy("serialNo").limit(5);
    first.get().then((querySnapshot) => {
      // Get the last visible document
      lastVisible = querySnapshot.docs[querySnapshot.docs.length-1];
      console.log("lastVisible", lastVisible);
      tableIndex = querySnapshot.size;
      document.getElementById("wallpaperCount").innerHTML = 'Total Items: ' + tableIndex + '';
      querySnapshot.forEach((doc) => {
        var productItem = Object.create(wallpapers);
        productItem.nodeId = doc.id;
        productItem.serialNo = doc.data().serialNo;
        productItem.title = doc.data().title;
        productItem.downloadNumber = doc.data().downloadNumber;
        productItem.isPremimumItem = doc.data().isPremimumItem;
        productItem.wallpaper1125_2436ImgName = doc.data().wallpaper1125_2436ImgName;
        productItem.wallpaper1242_2208ImgName = doc.data().wallpaper1242_2208ImgName;
        productItem.wallpaper1242_2688ImgName = doc.data().wallpaper1242_2688ImgName;
        productItem.wallpaper828_1792ImgName = doc.data().wallpaper828_1792ImgName;
        productItem.wallpaper750_1334ImgName = doc.data().wallpaper750_1334ImgName;
        productItem.wallpaper640_1136ImgName = doc.data().wallpaper640_1136ImgName;
        productItem.wallpaper1125_2436Url = doc.data().wallpaper1125_2436Url;
        productItem.wallpaper1242_2208Url = doc.data().wallpaper1242_2208Url;
        productItem.wallpaper1242_2688Url = doc.data().wallpaper1242_2688Url;
        productItem.wallpaper828_1792Url = doc.data().wallpaper828_1792Url;
        productItem.wallpaper750_1334Url = doc.data().wallpaper750_1334Url;
        productItem.wallpaper640_1136Url = doc.data().wallpaper640_1136Url;
        productItem.wallpaper1125_2436ImgStorageRef = doc.data().wallpaper1125_2436ImgStorageRef;
        productItem.wallpaper1242_2208ImgStorageRef = doc.data().wallpaper1242_2208ImgStorageRef;
        productItem.wallpaper1242_2688ImgStorageRef = doc.data().wallpaper1242_2688ImgStorageRef;
        productItem.wallpaper828_1792ImgStorageRef = doc.data().wallpaper828_1792ImgStorageRef;
        productItem.wallpaper750_1334ImgStorageRef = doc.data().wallpaper750_1334ImgStorageRef;
        productItem.wallpaper640_1136ImgStorageRef = doc.data().wallpaper640_1136ImgStorageRef;
        productItem.wallpaper1125_2436FacebookPhotoID = doc.data().wallpaper1125_2436FacebookPhotoID;
        productItem.wallpaper1242_2208FacebookPhotoID = doc.data().wallpaper1242_2208FacebookPhotoID;
        productItem.wallpaper1242_2688FacebookPhotoID = doc.data().wallpaper1242_2688FacebookPhotoID;
        productItem.wallpaper828_1792FacebookPhotoID = doc.data().wallpaper828_1792FacebookPhotoID;
        productItem.wallpaper750_1334FacebookPhotoID = doc.data().wallpaper750_1334FacebookPhotoID;
        productItem.wallpaper640_1136FacebookPhotoID = doc.data().wallpaper640_1136FacebookPhotoID;

        var row = table.insertRow(2);
        var cell1 = row.insertCell(0);
        var cell2 = row.insertCell(1);
        var cell3 = row.insertCell(2);
        var cell4 = row.insertCell(3);
        var cell5 = row.insertCell(4);
        var cell6 = row.insertCell(5);
        var cell7 = row.insertCell(6);
        var cell8 = row.insertCell(7);
        var cell9 = row.insertCell(8);
        var cell10 = row.insertCell(9);
        var cell11 = row.insertCell(10);
        cell1.innerHTML = productItem.serialNo;
        cell2.innerHTML = productItem.title;
        cell3.innerHTML = productItem.downloadNumber;
        cell4.innerHTML = productItem.isPremimumItem;
        appendImageOnCell(cell5, "./utilities/images/tick.png"); //productItem.wallpaper1125_2436Url
        appendImageOnCell(cell6, "./utilities/images/tick.png"); //productItem.wallpaper1242_2208Url
        appendImageOnCell(cell7, "./utilities/images/tick.png"); //productItem.wallpaper1242_2688Url
        appendImageOnCell(cell8, "./utilities/images/tick.png"); //productItem.wallpaper828_1792Url
        appendImageOnCell(cell9, "./utilities/images/tick.png"); //productItem.wallpaper750_1334Url
        appendImageOnCell(cell10, productItem.wallpaper640_1136Url);
        appendButtonOnCell(cell11, productItem);
      });
    });
  } else {
    var second = firestore.collection(parentNode).orderBy("serialNo").startAfter(lastVisible).limit(5);
    second.get().then((querySnapshot) => {
      // Get the last visible document
      lastVisible = querySnapshot.docs[querySnapshot.docs.length-1];
      console.log("lastVisible", lastVisible);
      tableIndex = tableIndex + querySnapshot.size;
      document.getElementById("wallpaperCount").innerHTML = 'Total Items: ' + tableIndex + '';
      querySnapshot.forEach((doc) => {
        var productItem = Object.create(wallpapers);
        productItem.nodeId = doc.id;
        productItem.serialNo = doc.data().serialNo;
        productItem.title = doc.data().title;
        productItem.downloadNumber = doc.data().downloadNumber;
        productItem.isPremimumItem = doc.data().isPremimumItem;
        productItem.wallpaper1125_2436ImgName = doc.data().wallpaper1125_2436ImgName;
        productItem.wallpaper1242_2208ImgName = doc.data().wallpaper1242_2208ImgName;
        productItem.wallpaper1242_2688ImgName = doc.data().wallpaper1242_2688ImgName;
        productItem.wallpaper828_1792ImgName = doc.data().wallpaper828_1792ImgName;
        productItem.wallpaper750_1334ImgName = doc.data().wallpaper750_1334ImgName;
        productItem.wallpaper640_1136ImgName = doc.data().wallpaper640_1136ImgName;
        productItem.wallpaper1125_2436Url = doc.data().wallpaper1125_2436Url;
        productItem.wallpaper1242_2208Url = doc.data().wallpaper1242_2208Url;
        productItem.wallpaper1242_2688Url = doc.data().wallpaper1242_2688Url;
        productItem.wallpaper828_1792Url = doc.data().wallpaper828_1792Url;
        productItem.wallpaper750_1334Url = doc.data().wallpaper750_1334Url;
        productItem.wallpaper640_1136Url = doc.data().wallpaper640_1136Url;
        productItem.wallpaper1125_2436ImgStorageRef = doc.data().wallpaper1125_2436ImgStorageRef;
        productItem.wallpaper1242_2208ImgStorageRef = doc.data().wallpaper1242_2208ImgStorageRef;
        productItem.wallpaper1242_2688ImgStorageRef = doc.data().wallpaper1242_2688ImgStorageRef;
        productItem.wallpaper828_1792ImgStorageRef = doc.data().wallpaper828_1792ImgStorageRef;
        productItem.wallpaper750_1334ImgStorageRef = doc.data().wallpaper750_1334ImgStorageRef;
        productItem.wallpaper640_1136ImgStorageRef = doc.data().wallpaper640_1136ImgStorageRef;
        productItem.wallpaper1125_2436FacebookPhotoID = doc.data().wallpaper1125_2436FacebookPhotoID;
        productItem.wallpaper1242_2208FacebookPhotoID = doc.data().wallpaper1242_2208FacebookPhotoID;
        productItem.wallpaper1242_2688FacebookPhotoID = doc.data().wallpaper1242_2688FacebookPhotoID;
        productItem.wallpaper828_1792FacebookPhotoID = doc.data().wallpaper828_1792FacebookPhotoID;
        productItem.wallpaper750_1334FacebookPhotoID = doc.data().wallpaper750_1334FacebookPhotoID;
        productItem.wallpaper640_1136FacebookPhotoID = doc.data().wallpaper640_1136FacebookPhotoID;

        var row = table.insertRow(tableIndex);
        var cell1 = row.insertCell(0);
        var cell2 = row.insertCell(1);
        var cell3 = row.insertCell(2);
        var cell4 = row.insertCell(3);
        var cell5 = row.insertCell(4);
        var cell6 = row.insertCell(5);
        var cell7 = row.insertCell(6);
        var cell8 = row.insertCell(7);
        var cell9 = row.insertCell(8);
        var cell10 = row.insertCell(9);
        var cell11 = row.insertCell(10);
        cell1.innerHTML = productItem.serialNo;
        cell2.innerHTML = productItem.title;
        cell3.innerHTML = productItem.downloadNumber;
        cell4.innerHTML = productItem.isPremimumItem;
        appendImageOnCell(cell5, "./utilities/images/tick.png"); //productItem.wallpaper1125_2436Url
        appendImageOnCell(cell6, "./utilities/images/tick.png"); //productItem.wallpaper1242_2208Url
        appendImageOnCell(cell7, "./utilities/images/tick.png"); //productItem.wallpaper1242_2688Url
        appendImageOnCell(cell8, "./utilities/images/tick.png"); //productItem.wallpaper828_1792Url
        appendImageOnCell(cell9, "./utilities/images/tick.png"); //productItem.wallpaper750_1334Url
        appendImageOnCell(cell10, productItem.wallpaper640_1136Url);
        appendButtonOnCell(cell11, productItem);
      });
    });
  }
}

What am I missing here?
Thanks!

My UI:
enter image description here

And this is the error I am getting:
enter image description here

2 Answers

Firstly instead of doing productItem.title = doc.data().title; and calling doc.data() a thousand times for every single possible field, you could just do:

let productItemLiteral = { nodeId: doc.id, ...doc.data() };
let productItem = Object.create(wallpapers, productItemLiteral);

And with regards to the pagination, you can paginate your fetches with query cursors. The firestore documentation handles this area very well: https://firebase.google.com/docs/firestore/query-data/query-cursors

Basically, your fetch function could look like this:

const fetchRecords = cursor => {
  const queryObj = cursor ?
    firestore().collection(parentNode).orderBy("serialNo").startAfter(cursor).limit(1 
 0)
    :
    firestore().collection(parentNode).orderBy("serialNo").limit(10);
  queryObj.get().then((querySnapshot => {
    // Save the last document to a global variable so you can use it as reference to fetch the next page
    lastDocCursor = querySnapshot.docs[querySnapshot.docs.length - 1];
    // Include the rest of your handler
  }
}

You should have a global variable: `lastDocCursor` initialized as `null`, so you could just call `fetchRecords(lastDocCursor);`. If a cursor already exists, it will fetch the next 10 documents that follow that document, if not, it will fetch the first 10

It looks like lastVisible is undefined, which is not allowed. When looking at your code, that makes sense, since you define lastVisible inside the fetchRequest function. So each time you call fetchRequest, you end up with a new lastVisible variable with an initial value of undefined.

You'll want to declare lastVisible outside of the fetchRequest method, so that its value is kept between calls to fetchRequest.

It also seems that you're duplicating a lot of code in fetchRequest. If we simplify this code and pull out the lastVisible variable, we end up with something like:

var lastVisible; // declare outside of fetchRequest so that its value is retained between calls
function fetchRequest(isFromLoadMore) {
  var query = firestore.collection(parentNode).orderBy("serialNo").limit(5);
  if (isFromLoadMore == false) {
    if (table.rows.length > 2) {
        resetTable(table);
    }
  }
  else if (lastVisible) {
    query = query.startAfter(lastVisible);
  }
  query.get().then((querySnapshot) => {
    // Get the last visible document
    lastVisible = querySnapshot.docs[querySnapshot.docs.length-1];
    console.log("lastVisible", lastVisible);

    ...
  });
}
Related