3
votes

After following the basic idea of this answer on SO Angular.js ng-repeat: opening/closing elements after x iterations

I'm grouping items and wrapping them in a div, and getting the following error Error: 10 $digest() iterations reached. Aborting! Watchers fired in the last 5 iterations:

This leads me to believe that Angular is expecting 10 repeats and is only registering 5. However, the output looks correct, all 10 items are shown.

I'm building a windows start screen type layout, where some of the tiles will be single, others double width. I'm doing some calculations to wrap the tiles in a div.

The filter I've built is

app.filter('partition', function() {
  var part = function(arr, size) {
    if ( 0 === arr.length ) return [];
    var applist=[];
    var partlist=[];
    var blocksize=0;
    console.log(arr);
    for(var a in arr){
        var app = arr[a];

        if(app.width=='single'){
            console.log(app.name);
            partlist.push(app);
            blocksize++;
        }
        if(app.width=='double' && blocksize=4){
            applist.push(partlist);
            partlist=[app];
            blocksize=2;
        }

        if(blocksize==size || a==arr.length-1){
                applist.push(partlist);
                partlist=[];
                blocksize=0;
            }
    }
    console.log(applist)
   return applist;
  };
  return part;
});

and the html with the ng-repeats are

<div ng-repeat="block in apps | filter:search | partition:6" class="app-block" >
    <li ng-repeat="app in block" class="app-tile" ng-class="{double:app.width=='double'}">
          <div class="name">{{app.name}}</div>
    </li>
</div>

Am I using the nested repeats wrong? As I said, the number of tiles being displayed is correct, but the error is what is concerning me (it's big, ugly and red).

1

1 Answers

4
votes

The root issue here is that your partition filter returns an array of arrays; each digest cycle, it returns a different array of arrays, even though the elements inside the internal arrays are the same.

For example, check this expression in your JavaScript console:

[[1, 2], [3, 4]] == [[1, 2], [3, 4]] // false

Because ngRepeat thinks the arrays are different each time, it continue re-runs a digest cycle, up until it reaches the maximum of 10.

If you have a Plunker or JSFiddle that provides a more complete, working picture of your problem, that would be helpful in demonstrating a solution; in lieu of that, check out this answer and also the accepted answer on that question.

One thing you can do is manipulate the data in the controller and iterate over that instead:

app.controller('SomeController', function($scope, $filter) {
  $scope.apps = [ ... ];

  var calculateBlocks = function() {
    var filteredBlocks = $filter('filter')($scope.search);
    $scope.appsBlocks = $filter('partition')(filteredBlocks, 6);
  };

  // Every time $scope.apps changes, set $scope.appsBlocks
  // to the filtered and partitioned version of that data.
  // In AngularJS 1.4+ you can use $watchCollection:
  // http://code.angularjs.org/1.1.4/docs/api/ng.$rootScope.Scope#$watchCollection
  $scope.$watch('apps', calculateBlocks, true);
  // Same if the search term changes.
  $scope.$watch('search', calculateBlocks);
});

Then in your HTML:

<div ng-repeat="block in appsBlocks" class="app-block" >
  <li ng-repeat="app in block" class="app-tile" ng-class="{double:app.width=='double'}">
    <div class="name">{{app.name}}</div>
  </li>
</div>