Search code examples
javascriptangularjsangularjs-ng-repeatangularjs-orderby

OrderBy and progressive-loading AngularJS


I'm having a problem when I use orderBy in a ng-repeat with an autoincrementing limitTo. When the page load a few elements the directive stops working and stops increasing the element limit.

This is the html:

<div class="row" id="main">
        <div class="col-xs-12 col-sm-6 col-md-3 col-lg-2 block animate"
             ng-if="!errorDialogActive"
             ng-repeat="build in builds.builds.build | limitTo:totalDisplayed | orderBy:'lastBuildDetails.startDate' : true track by build._id"
             ng-class="{'running': project.running ,'block-green': build._status ==='SUCCESS','block-red': build._status==='FAILURE'}"
             id="{{build._id}}"
             progressive-loading>
            <div class="title-container animate" ><p>{{build._buildTypeId}}</p></div>
            <div class="update-container animate col-xs-12">
            <time class="time">{{build.buildDate | date : 'dd.MM.yyyy H:mm:s'}} </time>
            </div>
        </div>
    </div>

This is the directive:

return function (scope) {
    if (scope.$last) {
        $timeout(function () {
            console.log('Im the last Displayed, Loading more');
            scope.loadMore();
        }, 100);
    }
};

And finally the loadMore function

    $scope.loadMore = function () {
        if ($scope.totalDisplayed >= $scope.size) {
            console.log('no more builds : ' + $scope.totalDisplayed);
            $scope.loaded=true;
        } else {
            $scope.totalDisplayed += 2;
            console.log('More : ' + $scope.totalDisplayed);
            $scope.totalDisplayedPercentage = (($scope.totalDisplayed*100)/$scope.size);
            console.log('Percentage : ' + $scope.totalDisplayedPercentage);
        }
    };

Sorry for my English, if you do not understand me or need more information, please let me know.


Solution

  • Your directive link function is calling only for a new rendered element, so when orderBy is work, new rendered element can placed in middle and special property scope.$last of course will be false, so just not starting timeout.

    For solving your can emulate counter, something like:
    NOTE: this simplest sample, possibly working correct only when one on page

    app.directive('progressiveLoading', ['$timeout', function ($timeout) { 
        var counter=1;
        return function (scope) { 
            if (counter == scope.displayStep) { 
                counter = 1;
                $timeout(function () { 
                    console.log('Im the last Displayed, Loading more'); 
                    scope.loadMore(); 
                }, 500); 
            }else{
                counter += 1;
            }
        }; 
    }]);
    

    Very simplified sample:

    // Code goes here
    var app = angular.module('app', []);
    
    app.directive('progressiveLoading', ['$timeout',
      function($timeout) {
        var counter = 1;
        return function(scope) {
          if (counter == scope.displayStep) {
            counter = 1;
            $timeout(function() {
              console.log('Im the last Displayed, Loading more');
              scope.loadMore();
            }, 500);
          } else {
            counter += 1;
          }
        };
      }
    ]);
    
    app.controller('ctrl', ['$scope',
      function($scope) {
        $scope.totalDisplayed = 2;
        $scope.displayStep = 2;
        $scope.loaded = false;
    
        $scope.build = [{
          _id: 1,
          _status: 'SUCCESS',
          lastBuildDetails: {
            startDate: 1
          },
          _buildTypeId: 1
        }, {
          _id: 2,
          _status: 'SUCCESS',
          lastBuildDetails: {
            startDate: 10
          },
          _buildTypeId: 2
        }, {
          _id: 3,
          _status: 'SUCCESS',
          lastBuildDetails: {
            startDate: 9
          },
          _buildTypeId: 3
        }, {
          _id: 4,
          _status: 'SUCCESS',
          lastBuildDetails: {
            startDate: 8
          },
          _buildTypeId: 4
        }, {
          _id: 5,
          _status: 'SUCCESS',
          lastBuildDetails: {
            startDate: 7
          },
          _buildTypeId: 5
        }, {
          _id: 6,
          _status: 'SUCCESS',
          lastBuildDetails: {
            startDate: 6
          },
          _buildTypeId: 6
        }, {
          _id: 7,
          _status: 'SUCCESS',
          lastBuildDetails: {
            startDate: 5
          },
          _buildTypeId: 7
        }, {
          _id: 8,
          _status: 'SUCCESS',
          lastBuildDetails: {
            startDate: 4
          },
          _buildTypeId: 8
        }, {
          _id: 9,
          _status: 'SUCCESS',
          lastBuildDetails: {
            startDate: 3
          },
          _buildTypeId: 9
        }, {
          _id: 10,
          _status: 'SUCCESS',
          lastBuildDetails: {
            startDate: 2
          },
          _buildTypeId: 10
        }];
        $scope.size = $scope.build.length;
        $scope.totalDisplayedPercentage = (($scope.totalDisplayed * 100) / $scope.size);
    
        $scope.loadMore = function() {
          console.log('loadMore', $scope.totalDisplayed, $scope.size);
          if ($scope.totalDisplayed >= $scope.size) {
            console.log('no more builds : ' + $scope.totalDisplayed);
            $scope.loaded = true;
          } else {
            $scope.totalDisplayed += $scope.displayStep;
            console.log('More : ' + $scope.totalDisplayed);
            $scope.totalDisplayedPercentage = (($scope.totalDisplayed * 100) / $scope.size);
            console.log('Percentage : ' + $scope.totalDisplayedPercentage);
          }
        };
      }
    ])
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
    
    <div class="row" id="main" ng-app="app" ng-controller="ctrl">
    <div>{{totalDisplayedPercentage}}%</div>  
      <div class="col-xs-12 col-sm-6 col-md-3 col-lg-2 block animate" ng-repeat="build in build | limitTo:totalDisplayed | orderBy:'lastBuildDetails.startDate' : true track by build._id" ng-class="{'running': project.running ,'block-green': build._status ==='SUCCESS','block-red': build._status==='FAILURE'}"
      id="{{build._id}}" progressive-loading="">
        <div class="title-container animate">
          <p>{{build._buildTypeId}}</p>
        </div>
      </div>
    </div>