Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement Infinite Scrolling with the new Firebase (2016)?

QUESTION:

How to implement efficient infinite scrolling in Firebase using javascript (and node.js) ?


WHAT I CHECKED:

Implementing Infinite Scrolling with Firebase?

Problem: older firebase ^

Infinite scroll with AngularJs and Firebase


CODE FROM: Infinite scroll with AngularJs and Firebase

"First, I recommend to create an Index in your Firebase. For this answer, I create this one:

{
   "rules": {
      ".read": true,
      ".write": false,
      "messages": {
         ".indexOn": "id"
      }
   }
}

Then, let's make some magic with Firebase:

// @fb: your Firebase.
// @data: messages, users, products... the dataset you want to do something with.
// @_start: min ID where you want to start fetching your data.
// @_end: max ID where you want to start fetching your data.
// @_n: Step size. In other words, how much data you want to fetch from Firebase.
var fb = new Firebase('https://<YOUR-FIREBASE-APP>.firebaseio.com/');
var data = [];
var _start = 0;
var _end = 9;
var _n = 10;
var getDataset = function() {
   fb.orderByChild('id').startAt(_start).endAt(_end).limitToLast(_n).on("child_added", function(dataSnapshot) {
      data.push(dataSnapshot.val());
   });
   _start = _start + _n;
   _end = _end + _n;
}

Finally, a better Infinite Scrolling (without jQuery):

window.addEventListener('scroll', function() {
  if (window.scrollY === document.body.scrollHeight - window.innerHeight) {
     getDataset();
  } 
});

I'm using this approach with React and it's blazing fast no matter how big your data is."

(answered Oct 26 '15 at 15:02)

(by Jobsamuel)


PROBLEM

In that solution, n posts will be loaded each time the scroll reaches the end of the height of screen.

Depending on screen sizes, this means a lot more posts than needed will be loaded at some point (the screen height only contains 2 posts, which means 3 more posts than necessary will be loaded each time we reach the end of the screen height when n = 5 for example).

Which means 3*NumberOfTimesScrollHeightHasBeenPassed more posts than needed will be loaded each time we reach the end of the scrollheight.


MY CURRENT CODE (loads all posts at once, no infinite scrolling):

var express = require("express");
var router = express.Router();

var firebase = require("firebase");

router.get('/index', function(req, res, next) {

    var pageRef = firebase.database().ref("posts/page");

    pageRef.once('value', function(snapshot){
        var page = [];
        global.page_name = "page";
        snapshot.forEach(function(childSnapshot){
            var key = childSnapshot.key;
            var childData = childSnapshot.val();
            page.push({
                id: key,
                title: childData.title,
                image: childData.image
            });
        });
        res.render('page/index',{page: page});
    });
});
like image 838
Coder1000 Avatar asked Oct 17 '22 23:10

Coder1000


1 Answers

Here is full code for infinite paging.

The function createPromiseCallback is for supporting both promises and callbacks.

function createPromiseCallback() {
  var cb;
  var promise = new Promise(function (resolve, reject) {
      cb = function (err, data) {
          if (err) return reject(err);
          return resolve(data);
      };
  });
  cb.promise = promise;
  return cb;
}

The function getPaginatedFeed implements actual paging

function getPaginatedFeed(endpoint, pageSize, earliestEntryId, cb) {
  cb = cb || createPromiseCallback();

 var ref = database.ref(endpoint);
  if (earliestEntryId) {
    ref = ref.orderByKey().endAt(earliestEntryId);
  }
  ref.limitToLast(pageSize + 1).once('value').then(data => {
    var entries = data.val() || {};

    var nextPage = null;
    const entryIds = Object.keys(entries);
    if (entryIds.length > pageSize) {
        delete entries[entryIds[0]];
        const nextPageStartingId = entryIds.shift();
        nextPage = function (cb) {
            return getPaginatedFeed(endpoint, pageSize, nextPageStartingId,                     cb);
        };
    }
    var res = { entries: entries, nextPage: nextPage };
    cb(null, res);
  });
  return cb.promise;
}

And here is how to use getPaginatedFeed function

var endpoint = '/posts';
var pageSize = 2;
var nextPage = null;
var dataChunk = null;
getPaginatedFeed(endpoint, pageSize).then(function (data) {
    dataChunk = data.entries;
    nextPage = data.nextPage;

    //if nexPage is null means there are no more pages left
    if (!nextPage) return;

    //Getting second page
    nextPage().then(function (secondpageData) {
        dataChunk = data.entries;
        nextPage = data.nextPage;
        //Getting third page
        if (!nextPage) return;

        nextPage().then(function (secondpageData) {
            dataChunk = data.entries;
            nextPage = data.nextPage;
            //You can call as long as your nextPage is not null, which means as long as you have data left
        });
    });

});

What about the question how many items to put on the screen, you can give a solution like this, for each post give fixed x height and if it requires more space put "read more" link on the bottom of the post which will reveal missing part when user clicks. In that case you can keep fixed count of items on your screen. Additionally you can check screen resolution in order to put more or less items.

like image 176
Vladimir Gabrielyan Avatar answered Nov 01 '22 12:11

Vladimir Gabrielyan