Search code examples
javascriptangularjsangularjs-directiveangular-directive

Angular directive: whats the difference between scope in controller vs scope in link function?


Im learning about Angular directives and I can't wrap my head around the scope topic. Suppose I have this custom directive which is named parentDirective. It has a controller property and a link property, as follows:

angular.module("app").directive("parentDirective", function () {
    return {
        restrict: "E",
        templateUrl: "dirs/parent.html",
        scope:{
            character: "="
        },
        controller: function ($scope) {
            $scope.getData = function (data) {
                console.log(data);
            }
        },
        link: function (scope,elem, attrs) {
            elem.bind("click", function (e) {
                //get object here?
            });
            scope.getData = function (data) {
                console.log(data);
            }
        }
    }
});

Its template is defined as follows:

<p ng-click="getData(character)">
    {{character.name}}
</p>

I can get the character object in the controller function through the $scope variable and I have access to the same data in the link function through scope. Whats the difference between the two methods in this regard? Second question, Is it possible to bind a click to the directive and get the object like this:

    elem.bind("click", function (e) {
        //get object here?
    });

Solution

  • Scope is specific to current directive instance and is the same object in both functions.

    For defining methods on the scope, there's no difference if they are defined in controller or link function, unless there is race condition that requires the method to be defined as early as possible. For this reason it makes sense to define scope methods in controller.

    Event handler doesn't differ from any other function, it is

    elem.on("click", function (e) {
      scope.$apply(function () {
        scope.character...
      });
    });
    

    scope.$apply(...) wrapper doesn't hurt anyway, but the necessity of it depends on what happens with scope.character.

    The directive can have only controller and no link. Current Angular versions (1.5+) suggest the style where bindToController + controllerAs are used instead of scope bindings as common ground for directives and components.

    Then the directive may look like

    restrict: "E",
    template: '<p>{{$ctrl.character.name}}</p>',
    controllerAs: '$ctrl',
    bindToController: { character: "=" },
    controller: function ($element, $scope) {
        var self = this;
    
        self.getData = function (data) { ... };
    
        $element.on("click", function (e) {
            scope.$apply(function () {
                self.character...
            });
        });
    }
    

    link function may appear as $postLink controller hook, but here it is not needed.