Samir Taha
Samir Taha

Reputation: 23

AngularJS Controller scope vs directive scope?

Please refer to this AngularJS example at plunker or at the code below

My first question:
In the accordion directive at line 40, why is the scope variable "expanders" reinitialized to an empty array as follows var expanders = []; after it was initialized originally in the SomeController at line 20?

My second question:
why they passed the directive scope at line 70 and 74 and not the element ?

as follows:

My third question: i moved all the code from the accordion controller to the link function of the expander directive and the app still working 100% , why they built the expanders array on the parent accordion directive if they could built it in the link function of the expander ? please refer to this new plunk

.expander {
  border: 1px solid black;
  margin: 1px;
  width: 250px;
}

.expander > .title {
  background-color: black;
  color: white;
  padding: .1em .3em;
  cursor: pointer;
}

.expander > .body {
  padding: .1em .3em;
}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
    "http://www.w3.org/TR/html4/loose.dtd">
<html ng-app='appModule'>
<head>
  <title>Accordion</title>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.js"></script>
  <link href="accordion.css" rel='stylesheet'>
</head>
  <body ng-controller='SomeController' >
    <accordion>
      <expander class='expander'
                ng-repeat='expander in expanders'
                expander-title='expander.title'>
        {{expander.text}}
      </expander>
    </accordion>
  </body>

<script>
  function SomeController($scope) {
    $scope.expanders = [
      {title: 'Click me to expand',
        text: 'Hi there folks, I am the content that was hidden but is now shown.'},
      {title: 'Click this',
        text: 'I am even better text than you have seen previously'},
      {title: 'No, click me!',
        text: 'I am text that should be seen before seeing other texts'}
    ];
  }

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

  appModule.directive('accordion', function() {
    return {
      restrict: 'EA',
      replace: true,
      transclude: true,
      template: '<div ng-transclude></div>',
      controller: function() {
        var expanders = [];

        this.gotOpened = function(selectedExpander) {
          angular.forEach(expanders, function(expander) {
            if (selectedExpander != expander) {
              expander.showMe = false;
            }
          });
        }

        this.addExpander = function(expander) {
          expanders.push(expander);
        }
      }
    }
  });
  appModule.directive('expander', function(){
    return {
      restrict: 'EA',
      replace: true,
      transclude: true,
      require: '^?accordion',
      scope: { title:'=expanderTitle' },
      template: '<div>' +
          '<div class="title" ng-click="toggle()">{{title}}</div>' +
          '<div class="body" ng-show="showMe" ng-transclude></div>' +
          '</div>',
      link: function(scope, element, attrs, accordionController) {
        scope.showMe = false;
        accordionController.addExpander(scope);

        scope.toggle = function toggle() {
          scope.showMe = !scope.showMe;
          accordionController.gotOpened(scope);
        }
      }
    }
  });
</script>
</html>

Upvotes: 2

Views: 382

Answers (1)

MaazKhan47
MaazKhan47

Reputation: 849

`$scope.expanders` is only visible in the scope of `SomeController`

while var expander in directive is local variable in directive it self. Don't get confused with bothof them. Take it as they have nothing to do with each other.

<body ng-controller='SomeController' >
    <accordion>
      <expander class='expander'
                ng-repeat='expander in expanders' <!-- expanders here refers to $scope.expanders in SomeController that has some data in it -->
                expander-title='expander.title'>
        {{expander.text}}
      </expander>
    </accordion>
</body>

Answer for Question 2

Because they are passing the title of expander to addExpander() function.

scope: { title:'=expanderTitle' }. They have defined scope like this in expander directive and in scope the have given title

Answer for Question 3

That is what general and preferred practice is. You just cannot(should not) put everything in a single function.

Upvotes: 1

Related Questions