I have the following example:
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
$scope.testMethod = function() {
alert('hi');
}
});
<!DOCTYPE html>
<html>
<head>
<script data-require="[email protected]" data-semver="1.5.0" src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular.min.js"></script>
</head>
<body ng-app="myApp">
<div ng-controller="myCtrl">
{{testMethod()}}
</div>
</body>
</html>
I have called the method only once in view template. But why is it executed twice?
Overview. The $http service is a core AngularJS service that facilitates communication with the remote HTTP servers via the browser's XMLHttpRequest object or via JSONP. For unit testing applications that use $http service, see $httpBackend mock. For a higher level of abstraction, please check out the $resource service ...
AngularJS can complement the server-side technology, ASP.NET MVC by simplifying and reducing the operations performed by the server. The JavaScript technology supports template engine, dependency injection and routing engine of its own.
The ng-click Directive in AngluarJS is used to apply custom behavior when an element is clicked. It can be used to show/hide some element or it can pop up an alert when the button is clicked.
AngularJS is an open-source JavaScript framework developed by Google. It helps you to create single-page applications, one-page web applications that only require HTML, CSS, and JavaScript on the client side.
When you use functions in binding expressions Angular will reevaluate the expression on every $digest phase. The reason behind this is that functions can return a response but there is no way for Angular to know if the result won't change in the next function call.
Angular ensures that it will show the latest correct up to date value in the only way possible in this case - by calling the function every time there is a change in the scope.
You'll see people calling this "$digest phase". It can occur due to many reasons. For the sake of this explanation I'm simplifying stuff. If you want to know more read https://docs.angularjs.org/guide/scope
As a general rule - avoid binding to a function. Instead remember the function response in a $scope
variable and bind to it instead. Binding many times to a function might lead to performance issues when bindings count grows in your project.
Let's change the post example. Open the console and run the code below.
var app = angular.module('myApp', []);
app.controller('myCtrl', function($scope) {
var i = 0;
$scope.testMethod = function() {
alert('hi');
i++;
return i; // Return a different value every time
}
});
<!DOCTYPE html>
<html>
<head>
<script data-require="[email protected]" data-semver="1.5.0" src="//cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.0/angular.js"></script>
</head>
<body ng-app="myApp">
<div ng-controller="myCtrl">
{{testMethod()}}
</div>
</body>
</html>
For the example purposes it's important for $scope.testMethod
to return different value every time it's called.
You'll notice the following:
After you see it multiple times the following error will appear:
Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting!
So, what happened? Every time we change the $scope
state here angular runs another digest phase until it "stabilizes" (there are no more changes). There is a limit on 10 consecutive $digest phases.
In the thread post angular calls $digest when the controller is attached and then, because we change the $scope, it calls one more digest. If we remove all the bindings from the code only one digest will occur.
We can easily check this. Remove the {{testMethod()}}
line from the example and then place a breakpoints in angular code: $digest, line 16700 (angular 1.5.0).
On this line you'll see if ((dirty || asyncQueue.length) && !(ttl--)) {
.
Your breakpoint will now be hit only once. Let's look 2 lines above. Angular team wrote an interesting comment there:
// `break traverseScopesLoop;` takes us to here
It's a self explanatory comment and if we go up to line 16629 we'll see
do { // "while dirty" loop
There is a variable in the code named "dirty" that creates a do...while
loop. While the scope is dirty (there are changes detected) you'll stay in this loop. A change is any change on any scope variable used in any way by any kind of binding ($watch).
That's why we have 2 $digest phases here.
You can find Angular 1.5 here. For debugging purposes I've switched to the non-minified versions.
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