I attached a function to the scope, and i wanted to run it in a binding, like this:
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
var count = 0;
$scope.f = function () {
count++;
return count;
}
}
html...
<div ng-controller="MyCtrl">
{{f()}}
</div>
but when i run it, the function returns 11, as you can check on this fiddle: http://jsfiddle.net/h4w4yc6L/
it seems like the function is running several times, even though i only call it once on the html, because my console complains about
angular.js:13920
Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
please do be aware that i am really newbie on angular! i don't know why this is happening, so I will be really glad if you provide me with information about why this happens, how to avoid this, and what is the right way to achieve this...
thanks in advance :)
Angular works by binding a model to view through a scope. Every so often, it will run a digest cycle on a scope to update the associated view. During the digest cycle, (almost) all bindings within that scope are reevaluated at least once - and possibly multiple times, since the digest cycle repeats multiple times if it thinks it needs to (if values aren't 'stable'). I recommend reading https://docs.angularjs.org/guide/scope, specifically the section on scope lifecycle.
Since you bind directly to the function expression {{f()}}
(see https://docs.angularjs.org/guide/expression), Angular will call the function every time it reevaluates the binding. Using the interpolation syntax {{}}
with functions that change the state of the controller or model is not recommended, since you do not control how often they are evaluated
I should first note that if you want the function to re-evaluate only on some user input (eg. click), use the appropriate binding (ng-click
), etc.
If you really want the function to be evaluated only once, you may want to evaluate it in the controller's constructor and store the resulting value. Eg.
function MyCtrl($scope) {
var count = 0;
$scope.f = function () {
count++;
return count;
}
$scope.g = f();
}
<div ng-controller="MyCtrl">
{{g}}
</div>
Or you can use ng-init
(See https://docs.angularjs.org/api/ng/directive/ngInit, and note the warning at the top)
So, with ng-init
, you might get
<div ng-controller="MyCtrl" ng-init="foo = f()">
{{foo}}
</div>
This is not the recommended pattern though.
Another option is to use one-time bindings (see the section on https://docs.angularjs.org/guide/expression titled One Time Bindings)
So, you could do something like
<div ng-controller="MyCtrl">
{{::f()}}
</div>