5

WHAT I TRIED (DOES NOT WORK CORRECTLY):

CODE:

<script>

    var app = angular.module('app', ['firebase']);

    app.controller('ctrl', function ($scope, $firebaseArray, $timeout) {


            $scope.data = [];
            var _n = Math.ceil(($(window).height() - 50) / (350)) + 1;
            var start = 0;
            var end = _n - 1;
            var lastScore = <%=lastScore%>;
            console.log("FIRST FIRST FIRST LAST SCORE:" + lastScore);
            var firstElementsLoaded = false;

            $scope.getDataset = function() {

                fb.orderByChild('score').endAt(lastScore).limitToLast(_n).on("child_added", function(dataSnapshot) {

                    lastScore = dataSnapshot.child("score").val() - 1;
                    console.log("LAST TOP LIKED:"+ lastScore);

                    $scope.data.push(dataSnapshot.val());
                    $scope.$apply();
                    console.log("THE VALUE:"+$scope.data);

                    $scope.data.splice(start, end).concat($scope.data.reverse());
                    $scope.$apply();
                    start = start + _n;
                    end = end + _n

                    firstElementsLoaded = true;
                });

            };

            $scope.getDataset();

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

    });

    // Compile the whole <body> with the angular module named "app"
    angular.bootstrap(document.body, ['app']);


QUESTION:

How do I revert the data client-side to get my posts from top to bottom according to their score (from highest to lowest)?


WHAT I WOULD LIKE TO ACHIEVE:

Get my posts in descending order according to score which is a bit trickier with the infinite scroll.

Coder1000
  • 4,071
  • 9
  • 35
  • 84
  • Couldn't you just use Array.sort with a comparator function? If this is some kind of framework API thing, you don't point that out, $scope makes it look like angular but I'm not sure here. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort – Tim Consolazio Jan 02 '17 at 20:52
  • @TimConsolazio I looked at the link and that sort() uses Unicode code points: I don't see how I could apply it to my case :( Thanks for the suggestion though ! ^^ – Coder1000 Jan 02 '17 at 20:56
  • Wait a sec, the comparator function can be used to do any kind of sort. Straight Array.sort will use the unicode comparison, but you can provide a function as an argument that can do any kind of comparison. Keep reading to the bottom of the page. I (and probably 90 out of every 100 other JS devs) have used this to very powerful effect for all kinds of things. You can sort objects, sort by other factors not even included in the objects themselves (like comparing to another array), pretty much anything. – Tim Consolazio Jan 02 '17 at 21:11
  • @TimConsolazio I see :) well, my issue is mostly as to when to actually call the sort in my code. To be more precise, when to call the scope.apply and to call the sort() in combination with the right Firebase func vars. If you can provide a snippet of code that produces the behaviour I am looking for, or suggest precise modifications, I will accept your answer :) Thx for the link ! – Coder1000 Jan 02 '17 at 21:42

2 Answers2

0

Since the posts are displayed in reverse order, you should reverse the order of "pages"(use endAt instead of startAt), and sort posts reversely in every page.

See also this answer

Example

Setup:

$scope.data = [];
var n = Math.ceil(($(window).height() - 50) / (350)) + 1;
var firstElementsLoaded = false;
var lastScore = MAX_SCORE, lastKey

Function for scroll event listener:

$scope.getDataset = function() {
  fb.orderByChild('score')
  .endAt(lastScore, lastKey)
  //endAt is inclusive, take one more for the n-th
  .limitToLast(n + firstElementsLoaded)
  .once('value', loadPosts)

  function loadPosts(snapshot) {
    var posts = snapshot.val()
    function compare(a, b) {
      if (posts[a].score != posts[b].score) {
        return b.score - a.score
      }
      if (a < b) return 1
      if (a > b) return -1
      return 0
    }

    //skip the post included by endAt
    var ordered = Object.keys(posts).sort(compare).slice(firstElementsLoaded)
    lastKey = ordered[ordered.length-1]
    lastScore = posts[lastKey].score

    ordered.forEach(function(key) {
      $scope.data.push(posts[key])
    })
    $scope.$apply();
    firstElementsLoaded = true;
  }
}

For a more elegant way, you may try store scores reversely, or use an additional value.

fb.orderByChild('reversedScore')

Community
  • 1
  • 1
DarkKnight
  • 5,651
  • 2
  • 24
  • 36
  • Thank you for your answer ! Why did you write `n + firstElementsLoaded` though ? `firstElementsLoaded` is a boolean. – Coder1000 Jan 07 '17 at 12:59
  • 1
    shorthand for `if (firstElementsLoaded) { n+1 } else { n }` – DarkKnight Jan 07 '17 at 13:18
  • I edited my question to show more code just to make sure there is no misunderstanding. – Coder1000 Jan 07 '17 at 17:38
  • The way you constructed your code is too different from my current structure. It will cost too much data. Could you please have a look at my updated question ? :D – Coder1000 Jan 07 '17 at 17:44
  • I ended up using a reversedScore property. I had thought of it, but hoped there was a better solution and that is why I asked my question. I will keep the bounty open until the end in case someone has a simple solution to offer that doesn't use a reversedScore, but for now the bounty is yours :D Thx ! Your code made me understand there is probably no simple solution to this, but I am going to keep the bounty open just in case. – Coder1000 Jan 07 '17 at 20:29
  • Updated the answer, sorry for unclear where should it be pasted. This example is intended to be used in the controller function. – DarkKnight Jan 08 '17 at 00:22
0

I ended up using an inversedScore property:

<script>

    var app = angular.module('app', ['firebase']);

    app.controller('ctrl', function ($scope, $firebaseArray, $timeout) {


            $scope.data = [];
            var _n = Math.ceil(($(window).height() - 50) / (350)) + 1;
            var firstElementsLoaded = false;
            var lastScore = -100000;


            $scope.getDataset = function() {

                fb.orderByChild('inversedScore').startAt(lastScore).limitToFirst(_n).on("child_added", function(dataSnapshot) {

                    lastScore = dataSnapshot.child("inversedScore").val() + 1;
                    console.log("LAST LIKE SCORE:"+ lastScore);

                    $scope.data.push(dataSnapshot.val());
                    $scope.$apply();
                    console.log("THE VALUE:"+$scope.data);

                    firstElementsLoaded = true;
                });

            };

            $scope.getDataset();

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

    });

    // Compile the whole <body> with the angular module named "app"
    angular.bootstrap(document.body, ['app']);

</script>
Coder1000
  • 4,071
  • 9
  • 35
  • 84