1

I am able to fire an event after ng-repeat finishes the first time. However, I am unable to make the event fire after every ng-repeat consistently. It would appear that the event doesn't occur if the ng-repeat is a subset of the previous ng-repeat data.

I found this answer which provides a hacky solution to this problem using a filter. Does anyone know of a better way to make an event fire after every ng-repeat completion?

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

app.controller('Ctrl', function($scope) {
  $scope.data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
  $scope.limit = 11;
  
  $scope.$on('ngRepeatFinished', function(ngRepeatFinishedEvent){
  alert('Repeat Finished!');
  });
});

app.directive('onFinishRender', function(){
  return function(scope, element, attr){
    if(scope.$last){
      scope.$emit('ngRepeatFinished');
    }
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>


<div ng-app="appname" ng-controller="Ctrl">
  <select ng-model="limit">
    <option ng-repeat="o in data"value="{{o}}">{{o}}</option>
  </select>
  <ul>
    <li ng-repeat="x in data | limitTo: limit" on-finish-render>{{x}}</li>
  </ul>
</div>
Community
  • 1
  • 1
wyattis
  • 1,287
  • 10
  • 21
  • should work on changes to model. i've used `$last` approach numerous times. try upgrading angular...that's a pretty old version you are using – charlietfl Jan 27 '16 at 01:04
  • @charlietfl this occurs in newer versions of angular too. I've also tried it with 1.4.8. – wyattis Jan 27 '16 at 17:10

1 Answers1

1

The reason the $last event is not triggered is because to increase performance ng-repeat actually doesn't rerender the elements since the already exists. As you can notice with your current code every time you increase the limit $last event is triggered but when decreasing it doesn't since ng-repeat is not rerendering those elements.

Since ng-repeat doesn't have an option to force a rerender a somewhat hacky solution would be to watch the limit variable and check if ng-repeat $index equals the limit (then we know we are on the last element) and then fire the event.

I have updated your directive like so:

.directive('onFinishRender', function($http) {
    return {
        restrict:'A',
        link:function(scope,element,attr){
            scope.$watch('limit', function() {
              if(scope.$index === scope.limit-1) {
                scope.$emit('ngRepeatFinished');
              }
            })
        }
    };
});

And off course we do -1 on limit since we are working with array index.

As with all $watch you should keep these to a minimum and it all depends on your app really if it is a performance decrease you can accept.

perry
  • 520
  • 4
  • 12