0

I am using the uib-accordion directive from ui-boostrap for AngularJS. I have a question about passing value out of the transcluded directive, uib-accordion-group.

When simply setting a variable to ng-model inside the accordion, it will be attached to the accordion scope, rather than the parent main scope, though it looks like it is in the main scope due to the transclude directive.

In order to pass the value inside the accordion out to the main scope, I need to do something like ng-model="$parent.$parent.$parent.data2 which seems wrong.

Is there a way to do it gracefully?

angular.module('ui.bootstrap.demo', ['ngAnimate', 'ui.bootstrap']);
angular.module('ui.bootstrap.demo').controller('AccordionDemoCtrl', function($scope) {

});
<!doctype html>
<html ng-app="ui.bootstrap.demo">

<head>
  <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.js"></script>
  <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular-animate.js"></script>
  <script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.14.3.js"></script>
  <script src="example.js"></script>
  <link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet">
</head>

<body>

  <div ng-controller="AccordionDemoCtrl">
    <script type="text/ng-template" id="group-template.html">
      <div class="panel {{panelClass || 'panel-default'}}">
        <div class="panel-heading">
          <h4 class="panel-title" style="color:#fa39c3">
          <a href tabindex="0" class="accordion-toggle" ng-click="toggleOpen()" uib-accordion-transclude="heading"><span
            ng-class="{'text-muted': isDisabled}">{{heading}}</span></a>
        </h4>
        </div>
        <div class="panel-collapse collapse" uib-collapse="!isOpen">
          <div class="panel-body" style="text-align: right" ng-transclude></div>
        </div>
      </div>
    </script>


    <uib-accordion close-others="oneAtATime">
      <uib-accordion-group heading="Static Header, initially expanded" is-open="true">
        <div>
          Simple data model
          <input type="text" ng-model="data" />Anti-pattern data2 model
          <input type="text" ng-model="$parent.$parent.$parent.data2" />
        </div>
        <div>
          I read "{{data}}" inside the accordion
        </div>
        <div>
          I read "{{data2}}" inside the accordion
        </div>
      </uib-accordion-group>
    </uib-accordion>
    <div>
      How do I read "{{data}}" OUTSIDE the accordion
    </div>
    <div>
      Data2 seems fine "{{data2}}" OUTSIDE the accordion
    </div>

  </div>
</body>

</html>
Andy
  • 1,231
  • 1
  • 15
  • 27

2 Answers2

3

I had a related issue quite recently, and I ended up modifying the ui-bootstrap-tpls-0.14.3.js file. On line 239 you can see I've added a property called 'model' to the accordion directive's scope object.

scope: {
  heading: '@',               // Interpolate the heading attribute onto this scope
  isOpen: '=?',
  isDisabled: '=?',
  model: '='                   // Custom property added
},

Then in the controller, I've added an object called item1 to the controller's scope and given it a property called name:

$scope.item1 = {
  name: 'test1'
};

Lastly, add a 'model' attribute to the accordion group directive and specify item1 as the value to pass into the accordion directive:

<uib-accordion-group model="item1" heading="Static Header, initially expanded" is-open="true">

You should now be able to set the object's property values in the accordion as well as access them outside of the directive.

Here's a plunk with your code modified to work.

http://plnkr.co/edit/44x8pH?p=preview

I'm not super happy with modifying the UI bootstrap file, but I couldn't come up with a better way to do it. Obviously you'll need to have your own copy of the file stored locally so you can modify it, and I'd suggest adding .custom to the filename to remind you that it's been modified. Probably pop in some comments too so you can migrate any changes you make to a future version of it in case you want to upgrade.

Chris
  • 355
  • 1
  • 8
-1

I know it may be very late, and a little bit of purpose, but I ran into a similar issue: I had a value to pass to the template. Inspired by Chris answer, I found a hack that does’nt change uib files:

I passed the value I want to ng-disable, which I used as a temporary variable.

<div uib-accordion-group ... is-disabled="color">

Then in my accordion template, I put isDisabled back to it’s default false value.

<div class="panel-heading" ng-init="color = isDisabled; isDisabled = false">

After this you can use the color angular variable anywhere in the template.

Here is the corresponding plunker : https://embed.plnkr.co/ExktoE4RCXFrn6SoYZIR/

note: It may also work to pass an object in which you have a value containing isDisabled wanted value ({foo: 'bar',.., isDisabled: true}). And then you pass this value back to isDisabled

Ulysse BN
  • 10,116
  • 7
  • 54
  • 82