As Gilian already said, the problem is that you have a fixed pitch that prevents your section element from automatically getting its height to fit all its contents (including the recently expanded accordion). The solution I can offer for this (which is also very similar to what Bootstrap does, as far as I can tell)
- Set the
section height to auto when the animation is finished, so if the nested divs expand, the section will expand correctly. - Re-set the fixed height in
section when the user tries to close it before setting its height to 0 so that the closing animation works correctly.
To complete the first part, you can simply define a function that adjusts the height of the section to auto and call it after the extension animation finishes.
var adjustHeightFunc = function() { var target = angular.element($document[0].querySelector("#" + scope.target))[0]; if (attrs.expanded) { var content = target.querySelector('.slideable_content'); target.style.height = 'auto'; } }
Since the extension animation takes 0.7 seconds, you can simply call the adjustHeightFunc function with a timeout of 0.8 seconds (I understand that this is not entirely optimal, since if you change the duration of the animation, you will also need to change this timeout, but this best solution i have found so far, any other suggestions are welcome). So at the end of your onClick function, you can:
$timeout(adjustHeightFunc, 800);
To make the second part, you should not set the height of the section to 0 when the section should be collapsed, but always set it to the height of its contents. After you do this, and if the section needs to be collapsed, you call a separate function using $ timeout with a value of 0 (so that it runs in a separate digest loop), which sets the height of the section to 0, thereby causing the animation to crash . Thus, your onClick function becomes something like this:
element.bind('click', function() { var content = target.querySelector('.slideable_content'); var y = content.clientHeight; target.style.height = y + 'px'; if(!attrs.expanded) { content.style.border = '1px solid rgba(0,0,0,0)'; content.style.border = 0; } else { $timeout(closeAccordionFunc, 0); } attrs.expanded = !attrs.expanded; $timeout(adjustHeightFunc, 800); });
See the updated Plunker .
EDIT: As you can see from the comment settings, executing closeAccordionFunc with a timeout of 0 does not work with all browsers. The workaround for this is to declare a CSS class that will set the height of the auto element (using !important to override the height set directly on the element) and use the Angular $animate to add / remove this class to the element and execute closeAccordionFunc after the class is deleted. Thus, the updated onClick function:
element.bind('click', function() { var content = target.querySelector('.slideable_content'); var y = content.clientHeight; target.style.height = y + 'px'; if(!attrs.expanded) { content.style.border = '1px solid rgba(0,0,0,0)'; content.style.border = 0; } else { $animate.removeClass(angular.element(target), 'auto', function(){$timeout(closeAccordionFunc);}); } attrs.expanded = !attrs.expanded; if (attrs.expanded) { $timeout(adjustHeightFunc, 800); } });
See also at Plunker .