1

Why does the following give the error:

Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!

Code

<div ng-app>
  <h2>Todo</h2>
  <div ng-controller="TodoCtrl">
      <span ng-bind="getText()"></span>
  </div>
</div>

function TodoCtrl($scope) {
  $scope.todos = [
    {text:'learn angular', done:true},
    {text:'build an angular app', done:false}];

    $scope.getText = function() {
        var names = $scope.todos.map(function(t) { 
            return t.text;
        });
        return names;
    }
  };

The code block is supposed to grab all todos and then render their names in a list using ng-bind. It works, but tons of digest iteration errors show up in console.

jsfiddle

fanhats
  • 777
  • 2
  • 10
  • 20

2 Answers2

1

It is really a bad practice to use a function evaluation in ng-bind, reason for this infinite digest cycle is because your digest cycle never gets settled. Everytime digest cycle happens ng-bind expression also runs and since the return value from ng-bind expression is always different (different object reference produced by array.map) it has to rerun the digest cycle again and it goes on until reached the max limit set, i.e 10.

In your specific case you could just set the names as a scope property and ng-bind="name".

   $scope.names = $scope.todos.map(function(t) { 
        return t.text;
    }).join();

As a general rule you can make sure you update the property name only when needed from your controller, example when an event occurs like adding a todo, removing a todo etc.. A typical scenario in this answer. You could also use interpolation instead of ng-bind and use function expression. {{}}. ie:

 $scope.getText = function() {
        return $scope.todos.map(function(t) { 
            return t.text;
        }).join();

    }

and

<span>{{getText()}}</span> <!--or even <span ng-bind="getText()"></span>-->

Fiddle

Community
  • 1
  • 1
PSL
  • 123,204
  • 21
  • 253
  • 243
  • That seems best when the controller deals with small amounts of data. Is that best practice in larger applications that may have 20+ other scope variables similar to `todos`? That would mean creating 2x the number of scope variables just to hold a subset of the already existing information. I thought calling a function that filters if for you would be easier? – fanhats Jan 25 '15 at 18:28
  • @fanhats There is something called viewmodel which is specifically for this purpose. But the idea is that you understand what is the issue that is causing this and what are the possible scenarions as i have covered in my answer. it is upto you to chose what you need. But _i really thought it is better to explain what is going on_ and also if you always evaluate a function expression in ng-bind/interpolate you need to remember it runs during every digest cycle and if you are doing an expensive stuff there it could just slow down your entire application. – PSL Jan 25 '15 at 18:29
  • `20+ other scope variables similar to todos` it really depends on how you design. You cannot just blindly say create a separate scope property for everything. There are numerous ways to display a data so it is upto you to chose what you need keeping in mind the digest cycle/ watches and performance. – PSL Jan 25 '15 at 18:31
  • @fanhats Also please see [this answer](http://stackoverflow.com/questions/28095610/why-would-a-hash-computation-using-cryptojs-cause-a-rootscopeinfdig-error-in-a/28095806#28095806) similar issue as yours. – PSL Jan 25 '15 at 18:36
1

I feel like you have over complicated this i have updated the fiddle with a working solution http://jsfiddle.net/U3pVM/12417/.

<div ng-app>
  <h2>Todo</h2>
  <div ng-controller="TodoCtrl">
      <div ng-repeat="todo in todos"> 
          <span >{{ todo.text}}</span>
      </div>

  </div>
</div>

function TodoCtrl($scope) {
  $scope.todos = [
    {text:'learn angular', done:true},
    {text:'build an angular app', done:false}];

  };
Rajdeep Dosanjh
  • 1,157
  • 1
  • 9
  • 20