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

AngularjsJavascript Framework

Angularjs Problem Overview


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.

Angularjs Solutions


Solution 1 - Angularjs

Please check this jsFiddle. (The code is basically the same you posted but I use an element instead of the window to bind the scroll events).

As far as I can see, there is no problem with the code you posted. The error you mentioned normally occurs when you create a loop of changes over a property. For example, like when you watch for changes on a certain property and then change the value of that property on the listener:

$scope.$watch('users', function(value) {
  $scope.users = [];
});

This will result on an error message:

> Uncaught Error: 10 $digest() iterations reached. Aborting!
Watchers > fired in the last 5 iterations: ...

Make sure that your code doesn't have this kind of situations.

update:

This is your problem:

<div ng-init="user.score=user.id+1"> 

You shouldn't change objects/models during the render or otherwise, it will force a new render (and consequently a loop, which causes the 'Error: 10 $digest() iterations reached. Aborting!').

If you want to update the model, do it on the Controller or on a Directive, never on the view. angularjs documentation recommends not to use the ng-init exactly to avoid these kinds of situations:

> Use ngInit directive in templates (for toy/example apps only, not > recommended for real applications)

Here's a jsFiddle with a working example.

Solution 2 - Angularjs

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);
}

Solution 3 - Angularjs

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 :)

Solution 4 - Angularjs

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);
});

Solution 5 - Angularjs

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

Solution 6 - Angularjs

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");
});

Solution 7 - Angularjs

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.

Solution 8 - Angularjs

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.

Solution 9 - Angularjs

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

Solution 10 - Angularjs

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

Solution 11 - Angularjs

i had the similar error, because i had defined

> ng-class="GetLink()"

instead of

> ng-click="GetLink()"

Solution 12 - Angularjs

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);

Solution 13 - Angularjs

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionChubby BoyView Question on Stackoverflow
Solution 1 - AngularjsbmleiteView Answer on Stackoverflow
Solution 2 - AngularjsNatus DrewView Answer on Stackoverflow
Solution 3 - AngularjsMichail MichailidisView Answer on Stackoverflow
Solution 4 - AngularjssquillmanView Answer on Stackoverflow
Solution 5 - AngularjsJed LynchView Answer on Stackoverflow
Solution 6 - AngularjsAllenView Answer on Stackoverflow
Solution 7 - AngularjsAlexView Answer on Stackoverflow
Solution 8 - AngularjsJDevView Answer on Stackoverflow
Solution 9 - AngularjsDavid DonariView Answer on Stackoverflow
Solution 10 - AngularjsZsoltiView Answer on Stackoverflow
Solution 11 - AngularjsSatish Kumar sonkerView Answer on Stackoverflow
Solution 12 - AngularjsaCMoFoCordView Answer on Stackoverflow
Solution 13 - Angularjsmichael hansen079View Answer on Stackoverflow