1

I have menu with sections and subsections, like this:

Section 1
   Sub 1.1
   Sub 1.2
Section 2
   Sub 2.1
   Sub 2.2

I want to hide subsections and show one of them by clicking on section (click on Section 2):

Section 1
Section 2
   Sub 2.1
   Sub 2.2

Here is my code and JSFiddle:

<div ng-controller="MyCtrl">
  <div ng-repeat="(meta, counts) in info">
      <a href="#" ng-click="display(meta)">{{ meta }}</a>
      <ul class="subsection">
          <li ng-repeat="(group, cnt) in counts"> 
              {{ group }} 
          </li>
      </ul>
  </div>
</div>

Controller:

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

//myApp.directive('myDirective', function() {});
//myApp.factory('myService', function() {});

function MyCtrl($scope) {
    $scope.name = 'Superhero';
    $scope.info = { "one": { "a": 1, "b": 2 },
                   "two" : { "c": 3, "d": 4 }};

    $scope.display = function(meta) {
        // ????
    };
}

CSS:

ul.subsection {
    display: none;
}

How can I fix this code to show one of the subsection by click on the section ?

Update: I fixed the link on JSFiddle

ceth
  • 44,198
  • 62
  • 180
  • 289

2 Answers2

2

Since ng-repeat creates its own scope, you can simply toggle a variable within the loop, and use ng-show on that variable:

<div ng-repeat="(meta, counts) in info">
  <a href="#" ng-click="display = !display">{{ meta }}</a>
  <ul class="subsection" ng-show="display">
      <li ng-repeat="(group, cnt) in counts"> 
          {{ group }} 
      </li>
  </ul>
</div>

Edit: If you can only show one function at a time, then you can do what you were trying to do in your original code with a function:

<div ng-repeat="(meta, counts) in info">
  <a href="#" ng-click="display($index)">{{ meta }}</a>
  <ul class="subsection" ng-show="sectionIndex == $index>
      <li ng-repeat="(group, cnt) in counts"> 
          {{ group }} 
      </li>
  </ul>
</div>

$scope.display = function(index) {
    $scope.sectionIndex = index;
}
tymeJV
  • 103,943
  • 14
  • 161
  • 157
  • Thanks. I have to show only one subsection at the time. Click section -> show this subsection and hide all others subsections. As I see in your solution the subsection will be visible until I click on the section one more time. – ceth Dec 20 '14 at 19:31
  • @demas - I added another chunk of code to do just that! – tymeJV Dec 20 '14 at 19:39
  • Using $index is much cleaner way to do it. – dfsq Dec 20 '14 at 19:43
1

You can simply do something like this:

<div ng-repeat="(meta, counts) in info">
    <a href="#" ng-click="$parent.display = meta">{{meta}}</a>
    <ul class="subsection" ng-show="$parent.display == meta">
        <li ng-repeat="(group, cnt) in counts">
            {{ group }}
        </li>
    </ul>
</div>

Note, that you can refer $parent scope to avoid local scope display property.

In this case you don't need CSS rule. Bonus point is that you can set in controller $scope.display = 'two' and the second item will expand.

However cleaner way would be using a controller function as demonstrated by @tymeJV, this is the best approach.

Demo: http://plnkr.co/edit/zXeWjXLGHMv0BZZRZtud?p=preview

dfsq
  • 191,768
  • 25
  • 236
  • 258
  • Thanks. Your solution is perfect, but I don't understand how does it work. What is the scope of $parent.display? They are different variables for each section ? – ceth Dec 20 '14 at 19:47
  • `ngRepeat` creates separate child scope on each iteration. The scope inside of each `div` is a child scope of the `$scope` in controller. It means that if you set `ng-click="display = meta` it will set child scope `display` property. However you need to set display of the scope shared by all `div` elements. That's why you can use `$parent` reference. Another option is to use a function declared in controller and use `$scope` there. So `$scope` in controller is the same scope you access in template with `$parent`. – dfsq Dec 20 '14 at 20:44