Skip to content
This repository was archived by the owner on May 29, 2019. It is now read-only.

Commit 3afcaa4

Browse files
feat(accordion): enable HTML in accordion headings
Defines a new directive <accordion-heading> that can be used below <accordion-group> elements to provide HTML to be transcluded into the group's heading. The transcluded headfng is compiled and linked to the same scope as the transcluded body - so it can contain AngularJS directives itself.
1 parent 6a97da2 commit 3afcaa4

File tree

3 files changed

+96
-12
lines changed

3 files changed

+96
-12
lines changed

src/accordion/accordion.js

+51-5
Original file line numberDiff line numberDiff line change
@@ -39,29 +39,34 @@ angular.module('ui.bootstrap.accordion', ['ui.bootstrap.collapse'])
3939
}
4040
};
4141

42-
}]);
42+
}])
4343

4444
// The accordion directive simply sets up the directive controller
4545
// and adds an accordion CSS class to itself element.
46-
angular.module('ui.bootstrap.accordion').directive('accordion', function () {
46+
.directive('accordion', function () {
4747
return {
4848
restrict:'EA',
4949
controller:'AccordionController',
5050
transclude: true,
5151
replace: false,
5252
templateUrl: 'template/accordion/accordion.html'
5353
};
54-
});
54+
})
5555

5656
// The accordion-group directive indicates a block of html that will expand and collapse in an accordion
57-
angular.module('ui.bootstrap.accordion').directive('accordionGroup', ['$parse', '$transition', '$timeout', function($parse, $transition, $timeout) {
57+
.directive('accordionGroup', ['$parse', '$transition', '$timeout', function($parse, $transition, $timeout) {
5858
return {
5959
require:'^accordion', // We need this directive to be inside an accordion
6060
restrict:'EA',
6161
transclude:true, // It transcludes the contents of the directive into the template
6262
replace: true, // The element containing the directive will be replaced with the template
6363
templateUrl:'template/accordion/accordion-group.html',
6464
scope:{ heading:'@' }, // Create an isolated scope and interpolate the heading attribute onto this scope
65+
controller: function($scope) {
66+
this.setHeading = function(element) {
67+
this.heading = element;
68+
};
69+
},
6570
link: function(scope, element, attrs, accordionCtrl) {
6671
var getIsOpen, setIsOpen;
6772

@@ -89,7 +94,48 @@ angular.module('ui.bootstrap.accordion').directive('accordionGroup', ['$parse',
8994
setIsOpen(scope.$parent, value);
9095
}
9196
});
97+
}
98+
};
99+
}])
92100

101+
// Use accordion-heading below an accordion-group to provide a heading containing HTML
102+
// <accordion-group>
103+
// <accordion-heading>Heading containing HTML - <img src="..."></accordion-heading>
104+
// </accordion-group>
105+
.directive('accordionHeading', function() {
106+
return {
107+
restrict: 'E',
108+
transclude: true, // Grab the contents to be used as the heading
109+
template: '', // In effect remove this element!
110+
replace: true,
111+
require: '^accordionGroup',
112+
compile: function(element, attr, transclude) {
113+
return function link(scope, element, attr, accordionGroupCtrl) {
114+
// Pass the heading to the accordion-group controller
115+
// so that it can be transcluded into the right place in the template
116+
// [The second parameter to transclude causes the elements to be cloned so that they work in ng-repeat]
117+
accordionGroupCtrl.setHeading(transclude(scope, function() {}));
118+
};
93119
}
94120
};
95-
}]);
121+
})
122+
123+
// Use in the accordion-group template to indicate where you want the heading to be transcluded
124+
// You must provide the property on the accordion-group controller that will hold the transcluded element
125+
// <div class="accordion-group">
126+
// <div class="accordion-heading" ><a ... accordion-transclude="heading">...</a></div>
127+
// ...
128+
// </div>
129+
.directive('accordionTransclude', function() {
130+
return {
131+
require: '^accordionGroup',
132+
link: function(scope, element, attr, controller) {
133+
scope.$watch(function() { return controller[attr.accordionTransclude]; }, function(heading) {
134+
if ( heading ) {
135+
element.html('');
136+
element.append(heading);
137+
}
138+
});
139+
}
140+
};
141+
});

src/accordion/test/accordionSpec.js

+44-6
Original file line numberDiff line numberDiff line change
@@ -104,12 +104,6 @@ describe('accordion', function () {
104104
describe('accordion-group', function () {
105105

106106
var scope, $compile;
107-
108-
beforeEach(inject(function(_$rootScope_, _$compile_) {
109-
scope = _$rootScope_;
110-
$compile = _$compile_;
111-
}));
112-
113107
var element, groups;
114108
var findGroupLink = function (index) {
115109
return groups.eq(index).find('a').eq(0);
@@ -118,6 +112,16 @@ describe('accordion', function () {
118112
return groups.eq(index).find('.accordion-body').eq(0);
119113
};
120114

115+
116+
beforeEach(inject(function(_$rootScope_, _$compile_) {
117+
scope = _$rootScope_;
118+
$compile = _$compile_;
119+
}));
120+
121+
afterEach(function () {
122+
element = groups = scope = $compile = undefined;
123+
});
124+
121125
describe('with static groups', function () {
122126
beforeEach(function () {
123127
var tpl =
@@ -257,5 +261,39 @@ describe('accordion', function () {
257261
expect(findGroupBody(1)[0].clientHeight).toBe(0);
258262
});
259263
});
264+
265+
describe('accordion-heading element', function() {
266+
beforeEach(function() {
267+
var tpl =
268+
'<accordion ng-init="a = [1,2,3]">' +
269+
'<accordion-group heading="I get overridden">' +
270+
'<accordion-heading>Heading Element <span ng-repeat="x in a">{{x}}</span> </accordion-heading>' +
271+
'Body' +
272+
'</accordion-group>' +
273+
'</accordion>';
274+
element = $compile(tpl)(scope);
275+
scope.$digest();
276+
groups = element.find('.accordion-group');
277+
});
278+
it('transcludes the <accordion-heading> content into the heading link', function() {
279+
expect(findGroupLink(0).text()).toBe('Heading Element 123 ');
280+
});
281+
it('attaches the same scope to the transcluded heading and body', function() {
282+
expect(findGroupLink(0).find('span').scope().$id).toBe(findGroupBody(0).find('span').scope().$id);
283+
});
284+
285+
});
286+
287+
describe('accordion-heading, with repeating accordion-groups', function() {
288+
it('should clone the accordion-heading for each group', function() {
289+
element = $compile('<accordion><accordion-group ng-repeat="x in [1,2,3]"><accordion-heading>{{x}}</accordion-heading></accordion-group></accordion>')(scope);
290+
scope.$digest();
291+
groups = element.find('.accordion-group');
292+
expect(groups.length).toBe(3);
293+
expect(findGroupLink(0).text()).toBe('1');
294+
expect(findGroupLink(1).text()).toBe('2');
295+
expect(findGroupLink(2).text()).toBe('3');
296+
});
297+
});
260298
});
261299
});
+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<div class="accordion-group">
2-
<div class="accordion-heading" ><a class="accordion-toggle" ng-click="isOpen = !isOpen">{{heading}}</a></div>
2+
<div class="accordion-heading" ><a class="accordion-toggle" ng-click="isOpen = !isOpen" accordion-transclude="heading">{{heading}}</a></div>
33
<div class="accordion-body" collapse="!isOpen">
44
<div class="accordion-inner" ng-transclude></div> </div>
55
</div>

0 commit comments

Comments
 (0)