How does one create an accordion dropdown menu in

2020-05-26 07:16发布

问题:

If you go to the https://material.angularjs.org website, you will notice a very nice Accordion dropdown menu in the sidenav.

I'm trying to find a simplified version of this feature. I've looked into many examples it appears many of them are no longer working.

I don't need it complicated. So no need of repetative items. I can do all that. I need the basic functionality.

From what I've researched they have an expando feature being developed, but until then is there a work around?

Updated:

I wasn't able to find a good angular material design, but I was able to find an angular method.

https://github.com/sherwaniusman/angular-accordion

回答1:

The following fiddle really helped me: Accordion example

I have also added functionality which allows expanding only 1 menu at a time, if others opened, it will automatically close them.

Code in Controller:

function controller($scope) {


     $scope.accordianData = [  
                                { "heading" : "About Us",         "content" : "" },
                                { "heading" : "Terms of Use",     "content" : "" },
                                { "heading" : "Privacy Policy",   "content" : "" },
                                { "heading" : "Help",             "content" : "" },
                             ];
      );
      // To expand or collapse the current view
      //This functionality automatically closes the other expanded lists
      $scope.toggleView = function(ary, data, index){
        for(var i=0; i<ary.length; i++){
          if(i!=index) { ary[i].expanded=false; }
          else { data.expanded=!data.expanded; }
        }
      }
  }

And the view/html Code is:
Just tweaked a bit of functionality as per my requirements:

<md-content id="dynamic-content" class="f-clear-padding">
      <div class="md-accordion" ng-repeat="data in accordianData">
        <!-- <md-toolbar ng-init="data.expanded = false" ng-click="data.expanded = !data.expanded"> this was the code in demo-->
        <md-toolbar ng-init="data.expanded = false" ng-click="toggleView(accordianData, data, $index)">
        <div class="md-toolbar-tools">
          <!-- <h2> -->
          <div ng-bind="data.heading"></div>
          <!-- </h2> -->
        <div flex=""></div>
        <div ng-class="{expandCollapse:true, active:data.expanded}"></div>
        </div>
        </md-toolbar>
        <div style="overflow:scroll" ng-class="{dataContent:true, activeContent:data.expanded}">
          <div style="padding:10px" ng-bind-html="data.content"></div>
        </div>
      <div>
    </md-content>

And the css part:

.md-accordion .expandCollapse { width:30px; height:30px; position:relative; font-size:20px; font-weight:bold; cursor:pointer; color:#fff; display:block; margin-top: -2px; margin-left: -2px; overflow:hidden; } 
.md-accordion .expandCollapse:active { border:0px; }
.md-accordion .expandCollapse:before, .md-accordion .expandCollapse:after { width:30px; height:30px; display:block; position:absolute; top:0; left:0; line-height:32px; text-align:center; -webkit-transition: .3s all ease-out; transition: .3s all ease-out; }
.md-accordion .expandCollapse:before { opacity:1 -webkit-transform: rotate(0deg); transform: rotate(0deg); content: "|"; margin-top:-3px; }
.md-accordion .expandCollapse:after { opacity:1; -webkit-transform: rotate(-90deg); transform: rotate(-90deg); content: "|"; margin-left:-3px; }
.md-accordion .active:before { opacity:1; -webkit-transform: rotate(90deg); transform: rotate(90deg); margin-left:3px; margin-top:0px; }
.md-accordion .dataContent { background: #F2F2F2; height:0px; overflow:hidden; -webkit-transition: .3s all ease-out; transition: .3s all ease-out; }
.md-accordion .activeContent { height:60vh; padding:0; display:block; }
.md-accordion md-toolbar{ cursor:pointer; border-bottom:1px solid rgb(63,107,181) }

Here we have fixed the height of the expandable list in order to keep the list items still visible, else once you expand a div having a huge content the user may feel that it's the only list item available and may not be able to see the other items if any of the div is expanded, the overflow:scroll allows the view to be scroll through, else it will be stiff and the user won't be ablt to view the entire content.

Hope this is helpful... :)



回答2:

So this is what I ended up using

Directive HTML Code

need a right and down arrow img

<ang-accordion one-at-a-time="true" icon-position="right" close-icon-url="<?php echo URL; ?>/img/icons/right-icon.png" open-icon-url="<?php echo URL; ?>/img/icons/down-icon.png">                                           
  <collapsible-item ng-repeat="item in items" item-title=""  initially-open="">                            

     <div>Text</div>

  </collapsible-item>             
</ang-accordion>

Script to include

<script type="text/javascript" src="<?php echo URL; ?>/js/angular/controllers/accordion.js"></script>

JS: accordion.js

app.controller('angAccordionController', ['$scope', function($scope){
    var collapsibleItems = [];

      this.openCollapsibleItem = function(collapsibleItemToOpen) {
        if( $scope.oneAtATime ) {
          angular.forEach(collapsibleItems, function(collapsibleItem) {
            collapsibleItem.isOpenned = false;
            collapsibleItem.icon = collapsibleItem.closeIcon;
          });
        }
        collapsibleItemToOpen.isOpenned = true;
      };

      this.addCollapsibleItem = function(collapsibleItem) {
        collapsibleItems.push(collapsibleItem);

        if ( $scope.closeIconClass !== undefined || $scope.openIconClass !== undefined ) {
          collapsibleItem.iconsType = 'class';
          collapsibleItem.closeIcon = $scope.closeIconClass;
          collapsibleItem.openIcon = $scope.openIconClass;
        }
        else if ( $scope.closeIconUrl !== undefined || $scope.openIconUrl !== undefined ) {
          collapsibleItem.iconsType = 'url';
          collapsibleItem.closeIcon = $scope.closeIconUrl;
          collapsibleItem.openIcon = $scope.openIconUrl;
        }

        collapsibleItem.iconIsOnLeft = $scope.iconPosition == 'left' ? true: false;
      };

  }])
  .directive('angAccordion', function() {
  return {
    restrict: 'EA',
    transclude: true,
    replace: true,
    scope: {
      oneAtATime: '@',
      closeIconUrl: '@',
      openIconUrl: '@',
      closeIconClass: '@',
      openIconClass: '@',
      iconPosition: '@' 
    },
    controller: 'angAccordionController',
    template: '<div class="accordion" ng-transclude></div>'
  };
});

angular.module('collapsibleItem', []).directive('collapsibleItem', function() {
  return {
    require: '^angAccordion',
    restrict: 'EA',
    transclude: true,
    replace: true,
    scope: {
      itemTitle: '@',
      itemDisabled: '=',
      initiallyOpen: '@'
    },
    link: function(scope, element, attrs, accordionController) {

      scope.isOpenned = (scope.initiallyOpen == "true") ? true : false;
      accordionController.addCollapsibleItem(scope);

      if(scope.isOpenned)
        scope.icon = scope.openIcon;
      else
        scope.icon = scope.closeIcon;

      scope.toggleCollapsibleItem = function () {

        if(scope.itemDisabled)
          return;

        if(!scope.isOpenned) {
          accordionController.openCollapsibleItem(this);
          scope.icon = scope.openIcon;
        }
        else {
          scope.isOpenned = false;
          scope.icon = scope.closeIcon;
        }
      };

      scope.getIconUrl = function ( type ) {
        return type == 'url' ? scope.icon : null;
      };
    },
    template: '<div class="collapsible-item" ng-class="{open: isOpenned}"><div class="title" ng-class="{disabled: itemDisabled}" ng-click="toggleCollapsibleItem()">{{itemTitle | limitTo:28 }}<i ng-show="iconsType == \'class\'" class="{{icon}} icon" ng-class="{iconleft: iconIsOnLeft}"></i><img ng-show="iconsType == \'url\'" class="icon" ng-class="{iconleft: iconIsOnLeft}" ng-src="{{getIconUrl(iconsType)}}" /></div><div class="body"><div class="content" ng-transclude></div></div></div>'
  };
});

CSS

.collapsible-item {
  margin-bottom: 0px;
}

.collapsible-item .title {
  padding: 10px;
  background-color: #dfdfdf;
  border: 0px solid #ccc;
  cursor: pointer;
}

.collapsible-item .title .icon {
  float: right;
  height: 20px;
  width: 20px;
  font-size: 19px !important;
  padding-right: 1px;
}

.collapsible-item .title .iconleft {
  float: left !important;
}

.collapsible-item .title.disabled {
  background: #eee;
  color: #999;
  cursor: text;
}

.collapsible-item .body {
  position: relative;
  top: -4px;
  max-height: 0;
  overflow: hidden;
  border: 1px solid #ccc;
  border-top: 0;
  z-index: -1;
  -webkit-transition: max-height 0.5s ease;
     -moz-transition: max-height 0.5s ease;
       -o-transition: max-height 0.5s ease;
          transition: max-height 0.5s ease;
}

.collapsible-item .body .content {
  padding: 5px 15px 5px 15px;
}

.collapsible-item.open .body {
  max-height: 1000px;
  z-index: 1;
}