1

I'm trying to construct an accordion list that shows more details when the accordion expands. Here is a simplified version of the template:

<body ng-controller="MainController as main">
    <accordion>
        <accordion-group ng-repeat="r in main.results" ng-controller="DetailsController as d">
            <accordion-heading ng-click="d.getDetails(r.id)">
                {{r.name}}
            </accordion-heading>
            <ul>
                <li ng-repeat="v in d.details">{{v.detail}}</li>
            </ul>
        </accordion-group>
    </accordion>
</body>

The DetailsController initially has an empty details array, but when the function getDetails() is called, that array is populated by a service (detailsService is simply an abstracted $resource call). This part works when not being applied to an accordion, but in this specific situation, nothing happens with the accordion heading is clicked. See below:

app.controller('DetailsController', function(detailsService) {
    var vm = this

    var details = []
    var detailsPopulated = false

    var getDetails = function(id) {
        console.log('getDetails()')
        if (!vm.detailsPopulated) {
            console.log('Getting details')
            detailsService.get({id: id}, function(data) {
                vm.details = data.results
                vm.detailsPopulated = true
            });
        }
    }

    return {
        details: details,
        getDetails: getDetails
    }

});

This controller works in other cases, but for some reason, the ng-click on the accordion header does not invoke the getDetails function at all - if it did, I would see "getDetails()" in the console, since that is the first statement of the getDetails function.

Even simpler: setting up a controller with mock "details" doesn't work.

app.controller('DetailsController', function() {
    var details = [{detail: 'Test'}]

    return {
        details: details
    }
});

Template:

<body ng-controller="MainController as main">
    <accordion>
        <accordion-group ng-repeat="r in main.results" ng-controller="DetailsController as d">
            <accordion-heading>
                {{r.name}}
            </accordion-heading>
            <ul>
                <li ng-repeat="v in d.details">{{v.detail}}</li>
            </ul>
        </accordion-group>
    </accordion>
</body>

Not even this simplified example with the service and ng-click removed works.

Can anyone advise a solution? I am also trying to accomplish this using the "controller as" technique instead of using $scope everywhere.

vimfluencer
  • 3,106
  • 3
  • 17
  • 25

1 Answers1

1

You can not bind ng-click to <accordion-heading> beacause ui.bootstrap will use different DOM for heading. You can take a look at developer console to see what ui.bootstrap translate <accordion-heading> into DOM.

<div class="panel-heading">
    <h4 class="panel-title">
    <a href="" class="accordion-toggle" ng-click="toggleOpen()" accordion-transclude="heading"><span class="ng-scope ng-binding">Header 1</span></a>
    </h4>
</div>

I think you want to dynamically load the content of accordion. One way to achieve this is to $watch when the accordion is opened and perform loading. I have created this fiddle to demonstrate the idea. Something you must notice :

  1. You can not put ng-controller inside accordion-group because it will raise error multiple directive asking for isolated scope. This is beacause <accordion-group> is an isolated scope and angular will not allow two scope : one from controller scope and one from directive isolated scope to bind into the same html. Reference. One way to work around it is to put a div with ng-controller and ng-repeat outside accordion-group

    <div ng-repeat="r in main.results" ng-controller="DetailsController as d">
        <accordion-group>
           ...
        </accordion-group>
    </div>
    
  2. You can add attrs is-open to accordion-group and $watch for its change and perform loading. Accordion directive will change is-open value when you open or close the accordion.

Hope it helps.

Community
  • 1
  • 1
themyth92
  • 1,743
  • 2
  • 17
  • 23