diff --git a/src/dropdown/docs/demo.html b/src/dropdown/docs/demo.html index f4feaa9588..f6c16fd542 100644 --- a/src/dropdown/docs/demo.html +++ b/src/dropdown/docs/demo.html @@ -55,11 +55,29 @@
  • Separated link
  • + + +
    + + +

    - + + diff --git a/src/dropdown/docs/readme.md b/src/dropdown/docs/readme.md index 47851ea1a3..8bfc8cf2f5 100644 --- a/src/dropdown/docs/readme.md +++ b/src/dropdown/docs/readme.md @@ -11,3 +11,7 @@ By default the dropdown will automatically close if any of its elements is click * `always` - (Default) automatically closes the dropdown when any of its elements is clicked. * `outsideClick` - closes the dropdown automatically only when the user clicks any element outside the dropdown. * `disabled` - disables the auto close. You can then control the open/close status of the dropdown manually, by using `is-open`. Please notice that the dropdown will still close if the toggle is clicked, the `esc` key is pressed or another dropdown is open. The dropdown will no longer close on `$locationChangeSuccess` events. + +Optionally, you may specify a template for the dropdown menu using the `template-url` attribute. This is especially useful when you have multiple similar dropdowns in a repeater and you want to keep your HTML output lean and your number of scopes to a minimum. The template has full access to the scope in which the dropdown lies. + +Example: ``. diff --git a/src/dropdown/dropdown.js b/src/dropdown/dropdown.js index de5cba6d8d..816629c98c 100644 --- a/src/dropdown/dropdown.js +++ b/src/dropdown/dropdown.js @@ -60,9 +60,10 @@ angular.module('ui.bootstrap.dropdown', ['ui.bootstrap.position']) }; }]) -.controller('DropdownController', ['$scope', '$attrs', '$parse', 'dropdownConfig', 'dropdownService', '$animate', '$position', '$document', function($scope, $attrs, $parse, dropdownConfig, dropdownService, $animate, $position, $document) { +.controller('DropdownController', ['$scope', '$attrs', '$parse', 'dropdownConfig', 'dropdownService', '$animate', '$position', '$document', '$compile', '$templateRequest', function($scope, $attrs, $parse, dropdownConfig, dropdownService, $animate, $position, $document, $compile, $templateRequest) { var self = this, scope = $scope.$new(), // create a child scope so we are not polluting original one + templateScope, openClass = dropdownConfig.openClass, getIsOpen, setIsOpen = angular.noop, @@ -131,9 +132,29 @@ angular.module('ui.bootstrap.dropdown', ['ui.bootstrap.position']) $animate[isOpen ? 'addClass' : 'removeClass'](self.$element, openClass); if ( isOpen ) { + if (self.dropdownMenuTemplateUrl) { + $templateRequest(self.dropdownMenuTemplateUrl).then(function(tplContent) { + templateScope = scope.$new(); + $compile(tplContent.trim())(templateScope, function(dropdownElement) { + var newEl = dropdownElement; + self.dropdownMenu.replaceWith(newEl); + self.dropdownMenu = newEl; + }); + }); + } + scope.focusToggleElement(); dropdownService.open( scope ); } else { + if (self.dropdownMenuTemplateUrl) { + if (templateScope) { + templateScope.$destroy(); + } + var newEl = angular.element(''); + self.dropdownMenu.replaceWith(newEl); + self.dropdownMenu = newEl; + } + dropdownService.close( scope ); } @@ -168,10 +189,16 @@ angular.module('ui.bootstrap.dropdown', ['ui.bootstrap.position']) restrict: 'AC', require: '?^dropdown', link: function(scope, element, attrs, dropdownCtrl) { - if ( !dropdownCtrl ) { + if (!dropdownCtrl) { return; } - dropdownCtrl.dropdownMenu = element; + var tplUrl = attrs.templateUrl; + if (tplUrl) { + dropdownCtrl.dropdownMenuTemplateUrl = tplUrl; + } + if (!dropdownCtrl.dropdownMenu) { + dropdownCtrl.dropdownMenu = element; + } } }; }) diff --git a/src/dropdown/test/dropdown.spec.js b/src/dropdown/test/dropdown.spec.js index 75ab9fa7c2..fc99695dbf 100644 --- a/src/dropdown/test/dropdown.spec.js +++ b/src/dropdown/test/dropdown.spec.js @@ -1,12 +1,13 @@ describe('dropdownToggle', function() { - var $compile, $rootScope, $document, dropdownConfig, element; + var $compile, $rootScope, $document, $templateCache, dropdownConfig, element; beforeEach(module('ui.bootstrap.dropdown')); - beforeEach(inject(function(_$compile_, _$rootScope_, _$document_, _dropdownConfig_) { + beforeEach(inject(function(_$compile_, _$rootScope_, _$document_, _$templateCache_, _dropdownConfig_) { $compile = _$compile_; $rootScope = _$rootScope_; $document = _$document_; + $templateCache = _$templateCache_; dropdownConfig = _dropdownConfig_; })); @@ -182,6 +183,30 @@ describe('dropdownToggle', function() { expect(element.hasClass(dropdownConfig.openClass)).toBe(false); }); }); + + describe('using dropdownMenuTemplate', function() { + function dropdown() { + $templateCache.put('custom.html', ''); + + return $compile('
  • ')($rootScope); + } + + beforeEach(function() { + element = dropdown(); + }); + + it('should apply custom template for dropdown menu', function() { + element.find('a').click(); + expect(element.find('ul.dropdown-menu').eq(0).find('li').eq(0).text()).toEqual('Item 1'); + }); + + it('should clear ul when dropdown menu is closed', function() { + element.find('a').click(); + expect(element.find('ul.dropdown-menu').eq(0).find('li').eq(0).text()).toEqual('Item 1'); + element.find('a').click(); + expect(element.find('ul.dropdown-menu').eq(0).find('li').length).toEqual(0); + }); + }); describe('using dropdown-append-to-body', function() { function dropdown() {