I implemented infinite scrolling in my web app using firebase.
In my "Top" section, I show the highest upvoted posts of users.
The issue, is that in my current implementation, a few posts are skipped.
That is, if many posts have the same score, some will just not appear.
I understand why this is happening, I load my posts by lot of 12, and then select the next lot by doing this:
start = childDataSnapshot.child("inversedScore").val() + 1;
The issue with this approach is that if there are more than 12 elements with the same vote score, or if there are 2 elements with the same vote score, one being number 12 and the other number 13, then number 13 gets ignored and we directly go the next score level.
For example, here is my data on the server:
post1: score: 15
post2: score: 14
post3: score: 13
post4: score: 12
post5: score: 11
post6: score: 10
post7: score: 10
post8: score: 9
post9: score: 9
post10: score: 9
post11: score: 8
post12: score: 7
//posts 13 and 14 will be ignored
post13: score: 7
post14: score: 7
post15: score: 6
post16: score: 6
Here is what I will see on the client:
post1: score: 15
post2: score: 14
post3: score: 13
post4: score: 12
post5: score: 11
post6: score: 10
post7: score: 10
post8: score: 9
post9: score: 9
post10: score: 9
post11: score: 8
post12: score: 7
post15: score: 6
post16: score: 6
What other approach is there to loading the top posts with firebase so that top posts with the same score are never "skipped" ?
client:
var started = false;
app.controller('ctrl', function ($scope, $firebaseArray, $timeout) {
if(started == false) {
started = true;
$scope.bricks = [];
var _n = 12;
if ( $(window).width() < 992) {
_n = 2;
}
var firstElementsLoaded = false;
var _start = -1000000000;
var position = 0;
$scope.getDataset = function() {
var sendObject = {
start: _start,
section: section,
n: _n,
}
$.ajax({
type: "POST",
url: "images/top",
data: sendObject,
}).done(function(result) {
for (var i = 0; i < result.array.length; i++) {
console.log("result: "+result.array[i]);
$scope.bricks.push(result.array[i]);
$scope.$apply();
}
_start = result.start;
firstElementsLoaded = true;
});
};
$scope.getDataset();
var screenHeight;
var existingScreenHeight
if ( $(window).width() < 992) {
screenHeight = (_n + 1) * 350;
existingScreenHeight = -350;
}
else {
screenHeight = 1 * Math.ceil($(window).height());
existingScreenHeight = -screenHeight;
}
window.addEventListener('scroll', function() {
if (firstElementsLoaded == true) {
if (window.scrollY >= ((screenHeight) + existingScreenHeight)) {
existingScreenHeight += (screenHeight);
$scope.$apply($scope.getDataset());
firstElementsLoaded = false;
}
}
});
}
});
angular.bootstrap(document.body, ['app']);
server:
router.post('/images/top', function(req, res, next) {
var start = parseInt(req.body.start);
var section = req.body.section;
var n = parseInt(req.body.n);
var returnArray = [];
var screenshotRef = admin.database().ref("posts/"+section);
screenshotRef.orderByChild("inversedScore").startAt(start).limitToFirst(n).once("value", function(dataSnapshot) {
dataSnapshot.forEach(function(childDataSnapshot) {
start = childDataSnapshot.child("inversedScore").val() + 1;
var post = childDataSnapshot.val();
var file = bucket.file(post.image);
var config = {
action: 'read',
expires: Date.now() + global.expiryTime,
};
file.getSignedUrl(config, function(err, url) {
if (err) {
console.error(err);
return;
}
post.image = url;
returnArray.push(post);
if (returnArray.length == n) {
var returnObject = {
start: start,
array: returnArray
}
res.send(returnObject);
}
});
});
});
});