6
      var self = this;
      var firebaseRef = new Firebase(baseUrl + '/sparks');

      firebaseRef.limitToLast(5).on('child_added', function(childSnapshot, prevChildKey) {
        self.addChild(childSnapshot); // adds post to a <div>
      });

database layout

My code currently loads the last 5 posts and will load any new posts. However, I'd also like to be able to load older posts as well. I have a button that when clicked will call a function (that I'm unsure of how to implement) that loads older posts. How do I retrieve these older posts?

(The arrow just signifies that I want to retrieve posts starting from the bottom and working my way up to the top)

Chris W
  • 785
  • 8
  • 18

2 Answers2

13

You need to think a bit backwards to do this. When you get the results for your query for the first page, remember the first item in the results:

firebaseRef.endAt().limitToLast(5).on('child_added', function(childSnapshot, prevChildKey) {
    self.addChild(childSnapshot); // adds post to a <div>
  });

While you cannot access child items by index with Firebase, you can store the key of an item and use that to start a next query.

var firstKnownKey;
firebaseRef.orderByKey().limitToLast(5).on('child_added', function(childSnapshot, prevChildKey) {
    if (!firstKnownKey) {
      firstKnownKey = childSnapshot.key;
    }
    self.addChild(childSnapshot); // adds post to a <div>
});

Now you have a variable firstKnownKey that has the first key you've ever seen. To get the previous batch of children, you pass that value in to endAt() when you fire your next query:

firebaseRef.orderByKey().endAt(firstKnownKey).limitToLast(5).on('child_added', function(childSnapshot, prevChildKey) {
    if (!firstKnownKey) {
      firstKnownKey = childSnapshot.key;
    }
    self.addChild(childSnapshot); // adds post to a <div>
});

Answers to similar questions of the past few days:

Community
  • 1
  • 1
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • Thanks, this was exactly what I needed. My issues were not using orderByKey(), using startAt instead of EndAt and limitToFirst instead of limitToLast! – Chris W Jan 31 '16 at 14:41
  • @Frank, your third piece of code will return every time the same result, because the `firstKnownKey` will be the same as when we getting the first batch. – Silviu Feb 28 '17 at 14:31
  • You will have to update `firstKnownKey` for each page that you load. – Frank van Puffelen Feb 28 '17 at 15:20
  • 1
    I have spent more than 8 hours getting this working. Can you, please give to us an more detailed example for this? I have this: https://i.imgur.com/7WTWxYu.png Getting first batch working fine, but after that I will receive duplicate sets of results and I don't know how to fix that. Thanks! – Silviu Feb 28 '17 at 16:27
  • 1
    @FinPercy Please use `` to get around the 6 character limit when editing. – Donald Duck Apr 27 '17 at 11:00
1

Since endAt() is inclusive, the last item gets repeated every time I do the infinite scroll, so I did a little modification to frank van puffen 's answer.

I initiate a list childrenVal to store all the values, another list childrenKey to store all the keys and a var firstKnownKey, as frank van puffen sugests.

var childrenVal=[];
var childrenKey=[];
var firstKnownKey = "";

For the first time you make the query, you get the last 5 elements:

getFirst(){
    firebaseRef.orderByKey().limitToLast(5).once('value')
        .then((snap)=>{
            snap.forEach(childSnap => {
                childrenVal.unshift(childSnap.val());
                childrenKey.unshift(childSnap.key);
            });
            firstKnownKey = childrenKey[childrenKey.length-1];
        });
}

In your next query, you won't want your firstKnownKey to get repeated, so I did the following function:

exclude(key){
    return key.substring(0, key.length - 1) + String.fromCharCode(key.charCodeAt(key.length - 1) - 1)
}

and for the query itself, the following function:

getNext() {
    firebaseRef.orderByKey().endAt(exclude(firstKnownKey)).limitToLast(5).once('value')
        .then((snap) => {
            snap.forEach(childSnap => {
                childrenVal.unshift(childSnap.val());
                childrenKey.unshift(childSnap.key);
            });
            firstKnownKey = childrenKey[childrenKey.length - 1];
        });
}
godlerner
  • 129
  • 1
  • 3