2

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:

  • line 70: accordionController.addExpander(scope);

  • line 74: accordionController.gotOpened(scope);

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>

1
  • Please embed the relevant code from your plunkr here in your question. Commented Jun 10, 2017 at 18:39

1 Answer 1

1
`$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.

Sign up to request clarification or add additional context in comments.

5 Comments

yes I think you are right those are two different things but the same name. but why in the expander directive they used the expander scope to build the model expanders and not the element from the link arguments.
I have given explanation for Question No 2. Kindly Mark it as green tick (accepted). If you find the answer helpful
thank you, but when I print the scope of the directive it gives me a whole object not just a simple model like the title for example.
also the scope object only include the title but not the body part why?
@SamirTaha you are passing only the title property through when using expander.title, when you look at the scope itself that is an object the properties you define in the scope of the directive are target properties of the scope object, the scope object has other methods associated with it for triggering a digest to update the view (through scope.$apply() ) and other things needed for cleaning up and dealing with events on the scope see the $rootScope documentation for all the details.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.