简体   繁体   中英

Collapse nested ng-repeat created divs

I am trying to achieve something like the image below. This is my data:

嵌套部分

JS:

angular.module('app', ['angular.filter'])
    .controller('MainController', function($scope) { 

    $scope.showReport = {};
    $scope.toggleShow = function (ym) {
        $scope.showReport[ym] = !$scope.showReport[ym];
    };

    $scope.Reports = [
        { Id: 1, Name: 'Report One', Year: 2016, Month: 5 },
        { Id: 2, Name: 'Report Core', Year: 2016, Month: 5 },
        { Id: 3, Name: 'Report Alpha', Year: 2016, Month: 3 },
        { Id: 4, Name: 'Report Moon', Year: 2015, Month: 5 },
        { Id: 5, Name: 'Report Sky', Year: 2015, Month: 2 }
    ];
});

HTML:

<ul ng-repeat="(key, value) in Reports | groupBy: 'Year'">
    {{ key }}
    <ul ng-repeat="(key1, value1) in value | groupBy: 'Month'">
        <a ng-click="toggleShow(key+key1)"> O{{key1}} </a>
        <li ng-repeat="p in value1" ng-if="!showReport[key+key1]">
            {{p.Name }} 
        </li>
    </ul>
</ul>

The objective is that if you click on any of the underlined numbers, the reports that belong to that month hide or show (collapsible). That's already done. This must also happen with the years- when you click a year, the months within must show/hide. I have tried many things but it seems I cannot figure it out what I need. I have made a JS BIN where my code is.

http://jsbin.com/huhabehoju/edit?html,js,output

Any help will be kindly appreciate it. Thanks

<!DOCTYPE html>
<html ng-app="app">
 <head>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.22/angular.min.js"></script>
  <script src="//cdnjs.cloudflare.com/ajax/libs/angular-filter/0.4.7/angular-filter.js"></script>

  <meta name="description" content="[groupBy example]"/>
  <meta charset="utf-8">
  <title>JS Bin</title>
</head>
<body>
  <div ng-controller="MainController"> 

   <ul ng-init= "yearhide=false" ng-repeat="(key, value) in Reports | groupBy: 'Year'">
     <li ng-click="yearhide = !yearhide">{{ key }}</li>
      <ul ng-hide="yearhide" ng-repeat="(key1, value1) in value | groupBy: 'Month'">
     <li ng-click="hideo = !hideo">O{{key1}} 
       <ul> 
        <li ng-show="hideo" ng-repeat="p in value1">
   {{p.Name }} 
       </li>
       </ul>
     </li>
    </ul>
   </ul>
  </div>
 </body>
</html>

try this jsbin link,here is demo

I have created a jsbin for you here .
I have added a new function that will hide and show the months based on your years.

$scope.showYears = {};
  $scope.toggleYear = function(year) {
    if ($scope.showYears[year] === undefined || $scope.showYears[year] === null)
      $scope.showYears[year] = false;
    else $scope.showYears[year] = !$scope.showYears[year];

  }
  $scope.showMonth = function(month, year) {
    if ($scope.showYears[year] === undefined || $scope.showYears[year] === null)
      return true;
    return $scope.showYears[year];
  }

The HTML has been kept as

<ul ng-repeat="(key, value) in Reports | groupBy: 'Year'">
  <div ng-click="toggleYear(key)">YEAR - {{ key }}</div>
  <ul ng-repeat="(key1, value1) in value | groupBy: 'Month'" ng-show="showMonth(key1, key)">
<a ng-click="toggleShow(key+key1)"> MONTH - {{key1}} </a>
<li ng-repeat="p in value1" ng-if="!showReport[key+key1]">
     {{p.Name }} 
 </li>
</ul>
</ul>

I cant see you toggleShow method, so I am assuming that you have already written the logic for that method.

can try this one no need to add any function in controller

<div>
   <ul ng-repeat="(key, value) in Reports | groupBy: 'Year'"  >
      <span ng-click="hideGroup[key] = !hideGroup[key]" style="cursor:pointer;">{{ key }}- {{value.show}}</span>
      <ul ng-hide="hideGroup[key]"  ng-repeat="(key1, value1) in value | groupBy: 'Month'">
         <span ng-click="hideGroup[key+key1] = !hideGroup[key+key1]" style="cursor:pointer;">O{{key1}}</span> 
         <li ng-hide="hideGroup[key+key1]" ng-repeat="p in value1">
            {{p.Name }} 
         </li>
      </ul>
  </ul>
</div>

Updated:

orderBy works only for array so at first you need to convert it to array. and orderBy should be last filter and you need to add filter in your controller so inject $filter in your controller. can see this example

In Controller:

  $scope.Reports= [];//your daata
  $scope.showReport = {};
  $scope.toggleShow = function (ym) {
      $scope.showReport[ym] = !$scope.showReport[ym];
  };
  $scope.desc = function(arr) {
    return $filter('min')
      ($filter('map')(arr, '-Year')); // descending by year
  };

in Html:

<ul ng-repeat="reports in Reports | groupBy: 'Year' | toArray:true | orderBy:desc">
     <li><span ng-click="toggleShow(reports[0].Year)" style="cursor:pointer">{{ reports[0].Year }}</span></li>
     <ul ng-hide="showReport[reports[0].Year]" ng-repeat="items in reports | groupBy: 'Month'">
          <li><span ng-click="toggleShow(reports[0].Year+items[0].Month)" style="cursor:pointer">O{{items[0].Month}} </span>
               <ul ng-hide="showReport[reports[0].Year+items[0].Month]"> 
                   <li  ng-repeat="item in items">
                           {{item.Name }} 
                   </li>
               </ul>
          </li>
     </ul>
</ul>

See Plunker Demo

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM