pje
pje

Reputation: 2468

AngularJS directive controller's scope accessible from outside directive, why?

Came across something interesting while experimenting. For some reason I am able to access the scope of a controller specified inside a directive declaration from outside the directive.

Here is the sample code:

myApp.directive('lockToggle', function () {
    return {
        restrict: 'A',
        link: function (scope, elem) {
            elem.bind('click', function (e) {
                scope.locked = !scope.locked;
                scope.$apply();
            });
        },
        controller: function ($scope) {
            $scope.locked = false;
            $scope.hello = function () {
                alert('hello');
            };
        }
    };
});

and here is my markup:

<button lock-toggle>
  Toggle Lock
</button>
<button ng-disabled="locked" ng-click="hello()">
  Click Me!
</button>

When I click on the button Toggle Lock, the Click Me! button disables and enables correctly. And, when I click the Click Me! button, the method hello() on the controllers scope is called.

My question is why? Shouldn't the scope of the controller declared in the directive be isolated to the directives scope in the html? I would expect it to behave in the same way as other controllers, e.g.:

<!--Can't access the scope of MyController-->

<div ng-controller="MyController">
  .    
  .
  <!--CAN access the scope of MyController-->
  .
  .
</div>

<!--Can't access the scope of MyController-->

But for some reason, this doesn't seem to apply to my earlier example above. Why is this?

Upvotes: 3

Views: 3467

Answers (2)

Zaheer Ahmed
Zaheer Ahmed

Reputation: 28578

The reason it is accessible is that you are adding it to same scope shared by your parent controller:

controller: function ($scope) {
    $scope.locked = false;
    $scope.hello = function () {
        alert('hello');
    };
}

Here $scope is of your parent controller and since in JavaScript object is by reference so you adding it to your parent controller.

If you want to initialize variable only for directive scope then use scope:

scope:{
  //properties
}

Upvotes: 1

Wottensprels
Wottensprels

Reputation: 3327

You can decide how your directive scope should behave and if it shall inherit from the parent scope:

myApp.directive('lockToggle', function () {
return {
    restrict: 'A',
    scope: {}, // Will create an isolated scope
    link: function (scope, elem) {
        elem.bind('click', function (e) {
            scope.locked = !scope.locked;
            scope.$apply();
        });
    },
    controller: function ($scope) {
        $scope.locked = false;
        $scope.hello = function () {
            alert('hello');
        };
    }
  };
});

Currently, you do not specify a scope attribute, which is equal to scope:false. Therefore, the directive does not create a scope.

Further information

Upvotes: 3

Related Questions