SavoryBytes
SavoryBytes

Reputation: 36256

Unable to call method on Angular isolate-scope directive

Given the following example, I'm curious why scope:true works as expected to toggle the elements. However, if scope:{} is used, the toggle method is not called by ng-click. Through my own experimentation it doesn't make a difference if you use bindToController and controllerAs or not, the problem is the same.

(function(angular) {
  'use strict';
  angular.module('test', [])
  .directive('collapsibleMenu', [function() {
    return {
      scope: {}, // doesn't work
      //scope: true, // works
      restrict: 'A',
      controller: function() {
        var ctrl = this;
        ctrl.open = false;
        ctrl.toggle = function() {
          ctrl.open = !ctrl.open;
          console.log('toggle', ctrl.open);
        }
      },
      bindToController: true,
      controllerAs: 'ctrl'
    };
  }]);
})(window.angular);
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.0-beta.1/angular.min.js"></script>
<div ng-app="test">
  <div collapsible-menu>
    <button ng-click="ctrl.toggle()">toggle menu 0</button>
    <ul role="menu" ng-show="ctrl.open" class="ng-cloak">
      <li><a href="#">link</a></li>
      <li><a href="#">link</a></li>
      <li><a href="#">link</a></li>
    </ul>
  </div>
  <div collapsible-menu>
    <button ng-click="ctrl.toggle()">toggle menu 1</button>
    <ul role="menu" ng-show="ctrl.open" class="ng-cloak">
      <li><a href="#">link</a></li>
      <li><a href="#">link</a></li>
      <li><a href="#">link</a></li>
    </ul>
  </div>
</div>

Upvotes: 2

Views: 507

Answers (3)

Shohel
Shohel

Reputation: 3934

you can use by this way

HTML:

<div ng-app="test">
        <div collapsible-menu>
            <button ng-click="toggle()">toggle menu 0</button>
            <ul role="menu" ng-show="open" class="ng-cloak">
                <li><a href="#">link</a></li>
                <li><a href="#">link</a></li>
                <li><a href="#">link</a></li>
            </ul>
        </div>
        <div collapsible-menu>
            <button ng-click="toggle()">toggle menu 1</button>
            <ul role="menu" ng-show="open" class="ng-cloak">
                <li><a href="#">link</a></li>
                <li><a href="#">link</a></li>
                <li><a href="#">link</a></li>
            </ul>
        </div>
    </div>

JS:

angular.module("test", []).
directive("collapsibleMenu", function () {
    return {
        restrict: "A",
        transclude: true,
        scope: {},
        link: function (scope, element, attrs, ctrl, transclude) {

            transclude(scope, function (clone) {
                element.append(clone);
            });

            scope.open = false;
            scope.toggle = function () {
                scope.open = !scope.open;
                console.log('toggle', scope.open);
            };
        }
    };
});

Upvotes: 0

a better oliver
a better oliver

Reputation: 26858

It's called isolat(ed) for a reason. The ctrl in the isolated scope is not the same as the ctrl in <button ng-click="ctrl.toggle()">.

I guess the misunderstanding stems from the fact that you think the content of <div collapsible-menu> is the content of the directive, but it's not. collapsible-menu is completely "isolated" (sic!) from the rest of the page.

Upvotes: 3

PhiLho
PhiLho

Reputation: 41162

I am not a master of directives and scope inheritance, but something that strikes me is that your directive isn't really one: it doesn't have a link function, and the code included in the tag should really be in a template. The repetition of the code inside the directive tag is a proof the directive is quite useless: you could as well declare directly the controller in the HTML itself.

Upvotes: 0

Related Questions