Lazy Angular-Bootstrap Accordions
Angular bootstrap accordions are great for menus and hiding things away, but they really do just hide the options: The elements still exist in the DOM. This means that if your menu is dynamically generated (eg. using ng-repeat) from a model in memory, these hidden DOM elements will still be checked and updated, whenever the model changes. If the accordion is closed, this can be a waste of processing time and slow down your UI, especially if you have a lot of <ng-repeats> inside the accordion.
To alleviate this problem, you can use the ng-if tag to only add the DOM elements to the accordion body when the accordion is open (lazy DOM adding). Use the is-open attribute to the accordion-group tag to specify a variable to keep track of when the accordion is open (eg. <accordion-group is-open="myAccordionIsOpen">) and then an ng-if on the element(s) inside the accordion (eg. ng-if="myAccordionIsOpen") to remove them from the DOM when the accordion is closed.
The final template should look something like this:
<accordion close-others="false"> <accordion-group heading="My Cool Accordion" is-open="openAccordions.coolAccordion"> <label ng-repeat="cool in cools" ng-if="openAccordions.coolAccordion"> <input type="checkbox" ng-model="cool.selected"> <span>{{ cool.name }}</span> </label> </accordion-group> </accordion>
This works, but the is-open variable doesn't get updated until after the "opening" animation has completed, so you see it slide open, finish opening, then the internals appear due to the ng-if evaluating. Since angular-ui's accordion tag doesn't support disabling animations, you need to override the template to change the collapse="!isOpen" attribute to ng-show="isOpen", so that ng-show (with no animation) is used to hide the internal content of the accordion instead of angular-bootstrap's collapse directive. To override the original template for the accordion wherever it is used, add this script tag at the end of your app.html:
<script id="template/accordion/accordion-group.html" type="text/ng-template"> <div class="accordion-group"> <div class="accordion-heading" ><a class="accordion-toggle" ng-click="isOpen = !isOpen" accordion-transclude="heading">{{heading}}</a></div> <div class="accordion-body" ng-show="isOpen"> <div class="accordion-inner" ng-transclude></div> </div> </div> </script>
You shouldn't use this everywhere, because the DOM elements still need to be added when the user clicks on the heading to open the accordion, and that can take some time, and you also lose the animation. But in many cases it saves time elsewhere to keep the DOM small and remove the elements that are not currently visible
I came up with this while contracting for Raiteas, a database visualization tool. If you want to see it in action, you can sign up for Raiteas and look at the nested accordions on the main page.













