1
votes

I have a parent component that creates "n" child components within an ng-repeat. Each child component has an accordion element (from ui-bootstrap directives) in its template.
From the parent component I would like to collapse or expand all accordions using a link in the parent component level. Each child accordion can be expanded/collapsed individually setting the local vm.isAccordionExpanded variable.

I am planning to use $scope.$broadcast() form the parent to notify the children, each of them will intercept the events with $scope.$on() and set a local boolean variable vm.isAccordionExpanded to open/close the accordion respectively.

Parent component template:

<span id="accordionListCommands" ng-if="vm.pastVisits.totalResults > 0">
    <span  id="collapseAllAccordion">
        <a ng-click="vm.collapseAll()" href="">
          <i class="fa fa-minus-square" aria-hidden="true"></i></a>
    </span>
    <span  id="expandAllAccordion">
        <a ng-click="vm.expandAll()" href=""> 
          <i class="fa fa-plus-square" aria-hidden="true"></i></a>
    </span>
</span>

<div ng-repeat="visitItem in vm.pastVisits.data">
    <visits-list-component visit="visitItem"></visits-list-component>
</div>

Parent component js file:

$scope.$on('collapse-all-accordion', function () {
    vm.isAccordionExpanded = false;
});

$scope.$on('expand-all-accordion', function () {
    vm.isAccordionExpanded = true;
});

Child template:

<uib-accordion close-others="false">
    <div uib-accordion-group is-open="vm.isAccordionExpanded">

//Rest of the template


Is there a better or more performant way to achieve this?

1
Looks like a good way. Always use track by in ng-repeat to increase performance. Also, you could use is-open="vm.isAccordionExpanded || allExpanded", and have the latter variable set to true to expand all. - Charleshaa
Thanks for reminding me about track bz Index, I edited the answer to show how I set the vm.isAccordionExpanded variable when the events are triggered. I think the logic is enough without adding allExpanded variable, or am I missing something? - Francesco
Yes your logic works great, it is just that instead of setting up multiple event listeners it will only do it during the digest cycle. Not sure about how much of performance you'll gain. Anyways your code looks fine to me. - Charleshaa

1 Answers

0
votes

The way you are doing this is not right and its not the angular way to write it. Instead use one way data binding or two way data binging:

bindings: {
  visit: '<' // or ('=') respectivly
}

and then implement your collapseAll function like follows:

angular.forEach( vm.pastVisits.data,function(visitItem) { 
  visitItem.isAccordionExpanded = false;
});

then in the visit component you can write:

vm.$onChanges = function() {
 if(changes.visit) {
   vm.isAccordionExpanded = changes.visit.currentValue.isAccordionExpanded;
 }

}

or even better without having to put $onChanges listener :

<uib-accordion close-others="false">
<div uib-accordion-group is-open="vm.visit.isAccordionExpanded">