1

I hope you guys can help me. Check out this short code.

<!DOCTYPE html>
<html ng-app="testApp">
    <head>
        <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.1/angular.js"></script>
        <script type="text/javascript">
            angular.module('testApp', [])
            .controller('testController', ['$scope', function ($scope) {
                $scope.greetMe = function(){
                    console.log('I\'ve been called')
                    return 'Greetings'
                };
            }]);
        </script>
    </head>
    <body>
        <div id="mainWrapper" data-ng-controller="testController">
            {{greetMe()}}
        </div>
    </body>
</html>

also at: http://plnkr.co/edit/K9fgNWcsm5gDvOfB19y6

If you run this in a browser (I tried chrome and firefox), your console shows
(2) I've been called.

I've tried this with angular 1.0.1, 1.2.0 and 1.3.0 rc.0

I discovered this behavior when I added a similar console.log in a method of a controller of a much bigger app that i'm trying to build. I got so shocked, because in my real case that expression is evaluated 6 times and even worse, all properties and all it's children's children are called/executed over and over again as well. In my specific case it seems that also each $http.get() call, triggers a new evaluation round.

Why ? Can I prevent that ?

Allisone
  • 8,434
  • 4
  • 32
  • 54

2 Answers2

1

It is because of angular dirty checking. Also usually we should avoid to call function from template whenever it is not required. When angular finished execution of this function, angular digest is called automatically which checks for all the models value for synchronization. However angular don't know that is there any model which is changing inside your function or not so angular calls that function again and checks if is there any model of current scope that is being updated, then it will sync that value to your template.

Jay Shukla
  • 5,794
  • 8
  • 33
  • 63
1

That's actually how AngularJS works with its $digest() loop. https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$digest

You probably shouldn't be calling your methods in the Angular Expressions to get a value from your scope.

It should look like this in the controller:

$scope.greeting = 'not greeted yet';

$scope.greet = function() {
    $scope.greeting = 'Greetings!!!';
};

And than you either call it by hand with a button:

<button ng-click="greet()">greet me</button>

Or if you need something that is initialized you do it directly in the controller like it did with:

$scope.greeting = 'not greeted yet';

See this edited Plunker: http://plnkr.co/edit/pG34sk5KryrphosVJFVB?p=preview

m.brand
  • 658
  • 5
  • 12