[angularjs] Error: 10 $digest() iterations reached. Aborting! with dynamic sortby predicate

I have the following code which repeats and displays the name of the user and his score:

<div ng-controller="AngularCtrl" ng-app>
  <div ng-repeat="user in users | orderBy:predicate:reverse | limitTo:10">
    <div ng-init="user.score=user.id+1">
        {{user.name}} and {{user.score}}
    </div>
  </div>
</div>

And the corresponding angular controller.

function AngularCtrl($scope) {
    $scope.predicate = 'score';
    $scope.reverse = true;
    $scope.users = [{id: 1, name: 'John'}, {id: 2, name: 'Ken'}, {id: 3, name: 'smith'}, {id: 4, name: 'kevin'}, {id: 5, name: 'bob'}, {id: 6, name: 'Dev'}, {id: 7, name: 'Joe'}, {id: 8, name: 'kevin'}, {id: 9, name: 'John'}, {id: 10, name: 'Ken'}, {id: 11, name: 'John'}, {id: 1, name: 'John'}, {id: 2, name: 'Ken'}, {id: 3, name: 'smith'}, {id: 4, name: 'kevin'}, {id: 5, name: 'bob'}, {id: 6, name: 'Dev'}, {id: 7, name: 'Joe'}, {id: 8, name: 'kevin'}, {id: 9, name: 'John'}, {id: 10, name: 'Ken'}]
}

When I run the above code, I get the Error: 10 $digest() iterations reached. Aborting! error in my console.

I have created jsfiddle for same.

The sort predicate is being initialized only inside the ng-repeat and also the limit is being applied on the number of objects. so I feel having both the sortby and limitTo watchers together is the reason for error.

If the $scope.reverse is false (ascending order of score), then it does not error.

Can anyone help me understand what is wrong here? Much appreciate your help.

This question is related to angularjs javascript-framework

The answer is


The cause of this error for me was...

ng-if="{{myTrustSrc(chat.src)}}"

in my template

It causes the function myTrustSrc in my controller to be called in an endless loop. If I remove the ng-if from this line, then the problem is solved.

<iframe ng-if="chat.src" id='chat' name='chat' class='chat' ng-src="{{myTrustSrc(chat.src)}}"></iframe>

The function is only called a few times when ng-if isn't used. I still wonder why the function is called more than once with ng-src?

This is the function in the controller

$scope.myTrustSrc = function(src) {
    return $sce.trustAsResourceUrl(src);
}

For me it was that I was passing a function result as 2-way binding input '=' to a directive that was creating a new object every time.

so I had something like that:

<my-dir>
   <div ng-repeat="entity in entities">
      <some-other-dir entity="myDirCtrl.convertToSomeOtherObject(entity)"></some-other-dir>
   </div>
</my-dir>

and the controller method on my-dir was

this.convertToSomeOtherObject(entity) {
   var obj = new Object();
   obj.id = entity.Id;
   obj.value = entity.Value;
   [..]
   return obj;
}

which when I made to

this.convertToSomeOtherObject(entity) {
   var converted = entity;
   converted.id = entity.Id;
   converted.value = entity.Value;
   [...]
   return converted;
}

solved the problem!

Hopefully this will help someone :)


I got the exact same error using AngularJS 1.3.9 when I, in my custom sort-filter invoked Array.reverse()

After I removed it, it wa sall good.


I got this error in the context of angular tree control. In my case it was the tree options. I was returning treeOptions() from a function. It was always returning the same object. But Angular magically thinks that its a new object and then cause a digest cycle to kick off. Causing a recursion of digests. The solution was to bind the treeOptions to scope. And assign it just once.


For starters ignore all answers with tell you to use $watch. Angular works off of a listener already. I guarantee you that you are complicating things by merely thinking in this direction.

Ignore all answers that tell you to user $timeout. You cannot know how long the page will take to load, therefore this is not the best solution.

You only need to know when the page is done rendering.

<div ng-app='myApp'>
<div ng-controller="testctrl">
    <label>{{total}}</label>
    <table>
      <tr ng-repeat="item in items track by $index;" ng-init="end($index);">
        <td>{{item.number}}</td>
      </tr>
    </table>
</div>

var app = angular.module('myApp', ["testctrl"]);
var controllers = angular.module("testctrl", []);
 controllers.controller("testctrl", function($scope) {

  $scope.items = [{"number":"one"},{"number":"two"},{"number":"three"}];

  $scope.end = function(index){
  if(index == $scope.items.length -1
        && typeof $scope.endThis == 'undefined'){

            ///  DO STUFF HERE
      $scope.total = index + 1;
      $scop.endThis  = true;
 }
}
});

Track the ng-repeat by $index and when the length of array equals the index stop the loop and do your logic.

jsfiddle


This happened to me after upgrading from angular 1.6 -> 1.7 when using $sce.trustAsResourceUrl() as the return value of a function called from ng-src. You can see this issue mentioned here.

In my case I had to change the following.

<source ng-src="{{trustSrc(someUrl)}}" type='video/mp4' />
trustSrc = function(url){
    return $sce.trustAsResourceUrl(url);
};

to

<source ng-src='{{trustedUrl}} type='video/mp4' />
trustedUrl = $sce.trustAsResourceUrl(someUrl);

If you use angular remove the ng-storage profile from your browser console. It is not a general solution bit It worked in my case.

In Chrome F12->Resources->Local Storage


I have another example of something that caused this. Hopefully it helps for future reference. I'm using AngularJS 1.4.1.

I had this markup with multiple calls to a custom directive:

<div ng-controller="SomeController">
    <myDirective data="myData.Where('IsOpen',true)"></myDirective>
    <myDirective data="myData.Where('IsOpen',false)"></myDirective>
</div>

myData is an array and Where() is an extension method that iterates over the array returning a new array containing any items from the original where the IsOpen property matches the bool value in the second parameter.

In the controller I set $scope.data like this:

DataService.getData().then(function(results){
    $scope.data = results;
});

Calling the Where() extension method from the directive like in the above markup was the problem. To fix this issue I moved the call to the extension method into the controller instead of the markup:

<div ng-controller="SomeController">
    <myDirective data="openData"></myDirective>
    <myDirective data="closedData"></myDirective>
</div>

and the new controller code:

DataService.getData().then(function(results){
    $scope.openData = results.Where('IsOpen',true);
    $scope.closedData = results.Where('IsOpen',false);
});

i had the similar error, because i had defined

ng-class="GetLink()"

instead of

ng-click="GetLink()"


It's weird ... I've got the exact same error, coming from a different thing. When I create my controller I passed the $location parameter, like this :

App.controller('MessageController', function ($scope, $http, $log, $location, $attrs, MessageFactory, SocialMessageFactory) {
   // controller code
});

This was proven to be a bug when we use third party libraries or pure JS to manipulate some specifics (here window.location) the next digest of angular will blow this error.

So I simply removed the $location from the controller creation parameter, and it worked again, without this error. Or if you absolutely need to use the $location from angular, you have to remove every single <a href="#">link</a> in the links of your template page, and rather write href="". Worked for me.

Hope it can help one day.


Pretty late to the party but my issue was happening because there is a defect in ui-router in angular 1.5.8. A thing to mention is that this error appeared only the first time I was running the application and it would not reoccur afterward. This post from github solved my issue. Basically the error involves $urlRouterProvider.otherwise("/home") The solution was a workaround like this:

$urlRouterProvider.otherwise(function($injector, $location) {
   var $state = $injector.get("$state");
   $state.go("your-state-for-home");
});

This happened to me right after upgrading Firefox to version 51. After clearing the cache, the problem has gone.