Search code examples
angularjsangularjs-directiveangularjs-scope

ng-init not working inside link function of directive?


According to this Plunkr, using ng-init in a directive won't execute a function assigned to scope inside link, but it will if I do it in controller.

Can anyone explain this?

app.js

var app = angular.module('app', []);

app.directive('linkDir', function(){
  return {
    restrict: 'E',
    scope: true,
    template: 'Link: <p ng-init="initLink()">{{ linkmsg  }}</p>',
    link: function(scope){
      scope.initLink = function(){
        scope.linkmsg = 'link function executed'
      }
    }
  };
});

app.directive('controllerDir', function(){
  return {
    restrict: 'E',
    scope: true,
    template: 'Controller: <p ng-init="initController()">{{ controllermsg  }}</p>',
    controller: function($scope){
      $scope.initController = function(){
        $scope.controllermsg = 'controller function executed';
      }
    }
  };
});

HTML

<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" href="style.css">
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.1/angular.min.js"></script>
    <script src="script.js"></script>
  </head>
  <body ng-app="app">
    <link-dir></link-dir>
    <controller-dir></controller-dir>
  </body>
</html>

Solution

  • This has to due with how Angular's directives work. The linkage between the scope and the DOM element is a little bit complex to explain, but making a long story short, if you use controllers, the scope will be immediately created with the initController property, while if you use the link attribute, the scope will only be populated after it as been linked to the DOM element (this means initLink will be undefined during the ng-init).

    In order to avoid these problems, don't use the ngInit directive, as stated on Angular's documentation:

    The only appropriate use of ngInit is for aliasing special properties of ngRepeat, as seen in the demo below. Besides this case, you should use controllers rather than ngInit to initialize values on a scope.

    Stick with Controllers if you need to init properties on the scope.