Search code examples
javascriptangularjsangular-directive

AngularJS - linking Fn is evaluated many times in directive


'use strict';

angular.module('app', [])

.controller('MainCtrl', function($scope) {
  console.log('heyo')
})

.directive('panel', function() {
  return {
    template: '<div ng-if="isAuthenticated()">Im In!</div>',
    restrict: 'E',
    scope: {},
    replace: true,
    link: function(scope, element, attrs) {

      var uid = 3

      scope.isAuthenticated = function() {
        console.log(uid)
        return uid !== null
      }

    }
  }
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.0-rc.4/angular.min.js"></script>

<div ng-app="app">
  <panel></panel>
</div>

My question is very simple and concise. The console.log is evaluated 50 times on my app, while only 2 here.

What is going on?

I think it's related, if not tied, to the $digest() cycle, but a more illuminated answer would be nice.


Solution

  • ngIf calls a $watch function on the provided expression, which is "isAuthenticated()" in your case.

    This expression will be called on every $digest call. see: https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$watch

    In the above link, please notice:

    The watchExpression is called on every call to $digest() and should return the value that will be watched.

    But also:

    Since $digest() reruns when it detects changes the watchExpression can execute multiple times per $digest() and should be idempotent

    Here you can watch how ngClick invokes digest resulting in ngIf evaluating it's expression http://jsfiddle.net/kihu/bbs8ajnk/2/

    This line logs the digest loops:

    $rootScope.$watch(function(){console.log("digest")}, function(){console.log('looped')});