I have a very simple Angular app setup, code as follows:
index.html
<!DOCTYPE html>
<html>
<head>
<script src='https://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js'></script>
<script src='app.js'></script>
</head>
<body ng-app="app">
<div ng-controller="MyCtrl">
<div ng-show="ready()">
Some content
</div>
</div>
</body>
</html>
And app.js
var app = angular.module('app', []);
app.controller('MyCtrl', function($scope) {
console.log("MyCtrl called")
$scope.ready = function() {
console.log("ready called");
return true;
}
})
If you run this with your console open you will see MyCtrl called once and ready called twice. I have spent hours trying to figure this out, I see no reason why $scope.ready
would be called anything but exactly one time.
If you use a Angular v1.1.5 and use ng-if
instead of ng-show
you will have the same behaviour, but if you use ng-init
it correctly calls $scope.ready
one time. In my case I will need ng-show
or ng-if
.
Plunkr: http://plnkr.co/edit/ZSwVNLeFSuhbouXZu9SM?p=preview
Clarification:
To elaborate on what I'm aiming for, let's say $scope.ready
at some point later returns false
(maybe it makes an AJAX call, that should NOT be called more than once), I would like "Some content" to no longer be visible. That is, dynamic behaviour based on the result of $scope.ready
.
Any ideas? Thank you for the help!
For the record this and this are not the same problem.
This is by design, not a bug (and it has nothing to do with the AngularJS compiler, as another answer incorrectly stated). ng-show
and ng-hide
work by "watching" changes of the expression ready()
.
At each digest cycle, for every watch, AngularJS evaluates the associated expression to see if there's any change and if there is, invoking the listener (in the case of ng-show
/ng-hide
, the listener will show or hide the element based on the value returned by ready()
).
Now, AngularJS can't just be satisfied with the first value returned by ready()
because during the same digest cycle, something (e.g. another watch expression) might actually make some change that causes whatever returned by ready()
to be a different value (e.g. by mutating an isReady
variable which is returned by ready()
). Obviously, developers would expect the latest value to be reflected to the DOM.
Therefore, AngularJS will evaluate every watch expression at least once to make sure that it is "stabilized" before finishing a digest cycle. Of course, this can lead to infinite digest iterations if an expression keeps changing, so AngularJS will throw an error if a digest cycle could not finish within 10 iterations.
There was a bug report on this, and the response was something to do with the compiler doing a double check
This is expected behavior. AngularJS does the call twice to ensure that the model has stabilized before rendering it.
There should be more info on why that is here http://docs.angularjs.org/guide/compiler
Bug Report: https://github.com/angular/angular.js/issues/1146
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With