Dynamic height animation with AngularJS

So, I'm trying to revive something like Angular Accordion, but without success. I figured this out with fixed heights, but not with dynamics. height: car; does not work.: (

Did some of you have a similar problem?

My code is:

HTML:      

  <head>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.3.15/angular-route.js"></script>
    <link rel="stylesheet" href="style.css">
    <script src="script.js"></script>
  </head>

  <body>
    <section ng-app="myApp">
    <div ng-controller="myCtrl as vm">
        <ul ng-init="vm.tab=1">
            <li ng-repeat="item in vm.data">
              <a href ng-click="vm.tab = item.thingy">{{item.name}}</a>
              <div ng-show="vm.tab === item.thingy">
                <img ng-src="{{item.img}}" width="50px"><br>
                <div class="longDiv">{{item.description}}</div>
              </div>
            </li>
        </ul>
    </div>
  </section>
</body>
</html>

JS:

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

app.controller('myCtrl', ['$scope',
  function($scope) {
    var vm = this;

    vm.data = [{
      name: "First",
      title: "oneTitle",
      description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit ipsum dolor sit amet, consectetur ipsum dolor sit amet, consectetur.",
      year: "2013",
      img: "http://static.hdw.eweb4.com/media/wp_400/1/5/42735.jpg",
      thingy: 1
    }, {
      name: "third",
      title: "twoTitle",
      description: "Quisque pulvinar libero sed eros ornare",
      year: "2014",
      img: "http://static.hdw.eweb4.com/media/wp_400/1/1/8519.jpg",
      thingy: 2
    }, {
      name: "Second",
      title: "threeTitle",
      description: "Cras accumsan ipsum dolor sit amet, consectetur ipsum dolor sit amet, consectetur ipsum dolor sit amet, consectetur massa vitae tortor vehicula .",
      year: "2015",
      img: "http://static.hdw.eweb4.com/media/wp_400/1/5/43326.jpg",
      thingy: 3
    }, {
      name: "fourth",
      title: "FourTitle",
      description: "Suspendisse ipsum dolor sit amet, consectetur ipsum dolor sit amet, consectetur ipsum dolor sit amet, consectetur ipsum dolor sit amet, consectetur ipsum dolor sit amet, consectetur ipsum dolor sit amet, consectetur ipsum dolor sit amet, consectetur ipsum dolor sit amet, consectetur vitae mattis magna.",
      year: "2011",
      img: "http://static.hdw.eweb4.com/media/wp_400/1/5/42413.jpg",
  thingy: 4
    }];

  }
]);

Thanks in advance! Plnkr here

+4
source share
5 answers

I solved this problem by creating the "collapse" directive:

ngModule.directive('collapse', [function () {
    return {
        restrict: 'A',

        link: function ($scope, ngElement, attributes) {
            var element = ngElement[0];

            $scope.$watch(attributes.collapse, function (collapse) {
                var newHeight = collapse ? 0 : getElementAutoHeight();

                element.style.height = newHeight +"px";
                ngElement.toggleClass('collapsed', collapse);
            });

            function getElementAutoHeight() {
                var currentHeight = getElementCurrentHeight();

                element.style.height = 'auto';
                var autoHeight = getElementCurrentHeight();

                element.style.height = currentHeight +"px";
                getElementCurrentHeight(); // Force the browser to recalc height after moving it back to normal

                return autoHeight;
            }

            function getElementCurrentHeight() {
                return element.offsetHeight
            }
        }
    };
}]);

To use this directive, you simply drop it on your element and set it to a scope variable that indicates whether to collapse it:

<div collapse="isCollapsed">
    This will be collapsed
</div>

CSS , . , , .

Codepen : http://codepen.io/KaidenR/pen/GoRJLx

+5

@kaiden, angular

require('./').directive('collapse', collapseDirective);

/**
* @ngInject
*/
function collapseDirective() {

   return {
    restrict: 'A',
    link: link
   };

   function link($scope, ngElement, attributes) {
     var element = ngElement[0];

     // set the height as a data attr so we can use it again later
     element.dataset.heightOld = angular.element(element).prop('offsetHeight');

     $scope.$watch(attributes.collapse, function (collapse) {
       var newHeight = !collapse ? 0 : element.dataset.heightOld;
       element.style.height = newHeight + 'px';
       ngElement.toggleClass('collapsed', collapse);
     }); 
   }
 }

, CSS- . , .

<ion-item class="item-accordion" collapse="vm.isActive($index)">

, ng-repeat . , , .

+3

, , jQuery angular, , .

$scope-accordion html:

vm.data = [{
  name     : "First",
  accordion: ["<h3>Title1</h3><div>Content 1</div><h3>Title2</h3><div>Content 1</div>"]};

, ng-repeat:

<div ng-repeat="item in vm.data>
    <div ng-repeat="acc in item.accordion" ng-bind-html="acc | normalHtml"></div>

, , div. setTimout, .

" , ".

, , .

, . , , :)

+1

Well, I think I found the holy grail. At least for my purposes :)

I'm having trouble using nested collapsed elements with a solution from @Kaiden and @Gareth Fuller, since any external collapse element would retain the original height that was obtained before all the internal collapse elements were collapsed. So I got inspiration from the @Icycool suggestion and changed to an animation at maximum height and kept the height in “auto”, which fixes this.

Below is a working demo.

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

testModule.controller('testController', function($scope) {
  $scope.isCollapsed = false;

  $scope.toggle = function() {
    $scope.isCollapsed = !$scope.isCollapsed;
  };
});

testModule.directive('collapse', [function() {
  return {
    restrict: 'A',

    link: function link($scope, $element, $attrs) {
      var element = $element[0];
      $element.addClass('collapse');
      const originalHeight = $element.prop('offsetHeight');

      $scope.$watch($attrs.collapse, function(collapse) {
        if (collapse) {
          element.style.maxHeight = '0px';
        } else {
          element.style.maxHeight = originalHeight + 'px';
        }
        $element.toggleClass('sh-collapsed', collapse);
      });
    }
  };
}]);
.collapse {
  height: 'auto';
  overflow: hidden;
  transition: max-height 0.3s;
  background: lightgreen;
}
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.4/angular.min.js"></script>
<div ng-app="testModule" ng-controller="testController">
  <button type="button" ng-click="toggle()">Toggle</button> Collapsed: {{isCollapsed}}
  <ul collapse="isCollapsed">
    <li>Line One</li>
    <li>Line Two</li>
    <li>Line Three</li>
    <li>Line Four</li>
    <li>Line Five</li>
  </ul>
</div>
Run codeHide result
0
source

All Articles