Andy Andy - 1 month ago 34
AngularJS Question

Passing value out of uib-accordion scope to the parent scope

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>




Answer

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.

Comments