@@ -42,6 +42,20 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Single button using append-to-body -->
|
||||
<div class="btn-group" dropdown dropdown-append-to-body>
|
||||
<button type="button" class="btn btn-primary dropdown-toggle" dropdown-toggle>
|
||||
Dropdown on Body <span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li><a href="#">Action</a></li>
|
||||
<li><a href="#">Another action</a></li>
|
||||
<li><a href="#">Something else here</a></li>
|
||||
<li class="divider"></li>
|
||||
<li><a href="#">Separated link</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
<p>
|
||||
<button type="button" class="btn btn-default btn-sm" ng-click="toggleDropdown($event)">Toggle button dropdown</button>
|
||||
|
||||
@@ -2,8 +2,13 @@
|
||||
Dropdown is a simple directive which will toggle a dropdown menu on click or programmatically.
|
||||
You can either use `is-open` to toggle or add inside a `<a dropdown-toggle>` element to toggle it when is clicked.
|
||||
There is also the `on-toggle(open)` optional expression fired when dropdown changes state.
|
||||
|
||||
Add `dropdown-append-to-body` to the `dropdown` element to append to the inner `dropdown-menu` to the body.
|
||||
This is useful when the dropdown button is inside a div with `overflow: hidden`, and the menu would otherwise be hidden.
|
||||
|
||||
By default the dropdown will automatically close if any of its elements is clicked, you can change this behavior by setting the `auto-close` option as follows:
|
||||
|
||||
* `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.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
angular.module('ui.bootstrap.dropdown', [])
|
||||
angular.module('ui.bootstrap.dropdown', ['ui.bootstrap.position'])
|
||||
|
||||
.constant('dropdownConfig', {
|
||||
openClass: 'open'
|
||||
@@ -60,13 +60,14 @@ angular.module('ui.bootstrap.dropdown', [])
|
||||
};
|
||||
}])
|
||||
|
||||
.controller('DropdownController', ['$scope', '$attrs', '$parse', 'dropdownConfig', 'dropdownService', '$animate', function($scope, $attrs, $parse, dropdownConfig, dropdownService, $animate) {
|
||||
.controller('DropdownController', ['$scope', '$attrs', '$parse', 'dropdownConfig', 'dropdownService', '$animate', '$position', '$document', function($scope, $attrs, $parse, dropdownConfig, dropdownService, $animate, $position, $document) {
|
||||
var self = this,
|
||||
scope = $scope.$new(), // create a child scope so we are not polluting original one
|
||||
openClass = dropdownConfig.openClass,
|
||||
getIsOpen,
|
||||
setIsOpen = angular.noop,
|
||||
toggleInvoker = $attrs.onToggle ? $parse($attrs.onToggle) : angular.noop;
|
||||
toggleInvoker = $attrs.onToggle ? $parse($attrs.onToggle) : angular.noop,
|
||||
appendToBody = false;
|
||||
|
||||
this.init = function( element ) {
|
||||
self.$element = element;
|
||||
@@ -79,6 +80,15 @@ angular.module('ui.bootstrap.dropdown', [])
|
||||
scope.isOpen = !!value;
|
||||
});
|
||||
}
|
||||
|
||||
appendToBody = angular.isDefined($attrs.dropdownAppendToBody);
|
||||
|
||||
if ( appendToBody && self.dropdownMenu ) {
|
||||
$document.find('body').append( self.dropdownMenu );
|
||||
element.on('$destroy', function handleDestroyEvent() {
|
||||
self.dropdownMenu.remove();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
this.toggle = function( open ) {
|
||||
@@ -109,6 +119,15 @@ angular.module('ui.bootstrap.dropdown', [])
|
||||
};
|
||||
|
||||
scope.$watch('isOpen', function( isOpen, wasOpen ) {
|
||||
if ( appendToBody && self.dropdownMenu ) {
|
||||
var pos = $position.positionElements(self.$element, self.dropdownMenu, 'bottom-left', true);
|
||||
self.dropdownMenu.css({
|
||||
top: pos.top + 'px',
|
||||
left: pos.left + 'px',
|
||||
display: isOpen ? 'block' : 'none'
|
||||
});
|
||||
}
|
||||
|
||||
$animate[isOpen ? 'addClass' : 'removeClass'](self.$element, openClass);
|
||||
|
||||
if ( isOpen ) {
|
||||
@@ -142,6 +161,19 @@ angular.module('ui.bootstrap.dropdown', [])
|
||||
};
|
||||
})
|
||||
|
||||
.directive('dropdownMenu', function() {
|
||||
return {
|
||||
restrict: 'AC',
|
||||
require: '?^dropdown',
|
||||
link: function(scope, element, attrs, dropdownCtrl) {
|
||||
if ( !dropdownCtrl ) {
|
||||
return;
|
||||
}
|
||||
dropdownCtrl.dropdownMenu = element;
|
||||
}
|
||||
};
|
||||
})
|
||||
|
||||
.directive('dropdownToggle', function() {
|
||||
return {
|
||||
require: '?^dropdown',
|
||||
|
||||
@@ -9,6 +9,10 @@ describe('dropdownToggle', function() {
|
||||
$document = _$document_;
|
||||
}));
|
||||
|
||||
afterEach(function() {
|
||||
element.remove();
|
||||
});
|
||||
|
||||
var clickDropdownToggle = function(elm) {
|
||||
elm = elm || element;
|
||||
elm.find('a[dropdown-toggle]').click();
|
||||
@@ -50,7 +54,6 @@ describe('dropdownToggle', function() {
|
||||
var optionEl = element.find('ul > li').eq(0).find('a').eq(0);
|
||||
optionEl.click();
|
||||
expect(element.hasClass('open')).toBe(false);
|
||||
element.remove();
|
||||
});
|
||||
|
||||
it('should close on document click', function() {
|
||||
@@ -66,7 +69,6 @@ describe('dropdownToggle', function() {
|
||||
triggerKeyDown($document, 27);
|
||||
expect(element.hasClass('open')).toBe(false);
|
||||
expect(isFocused(element.find('a'))).toBe(true);
|
||||
element.remove();
|
||||
});
|
||||
|
||||
it('should not close on backspace key', function() {
|
||||
@@ -180,6 +182,26 @@ describe('dropdownToggle', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('using dropdown-append-to-body', function() {
|
||||
function dropdown() {
|
||||
return $compile('<li dropdown dropdown-append-to-body><a href dropdown-toggle></a><ul class="dropdown-menu" id="dropdown-menu"><li><a href>Hello On Body</a></li></ul></li>')($rootScope);
|
||||
}
|
||||
|
||||
beforeEach(function() {
|
||||
element = dropdown();
|
||||
});
|
||||
|
||||
it('adds the menu to the body', function() {
|
||||
expect($document.find('#dropdown-menu').parent()[0]).toBe($document.find('body')[0]);
|
||||
});
|
||||
|
||||
it('removes the menu when the dropdown is removed', function() {
|
||||
element.remove();
|
||||
$rootScope.$digest();
|
||||
expect($document.find('#dropdown-menu').length).toEqual(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('integration with $location URL rewriting', function() {
|
||||
function dropdown() {
|
||||
|
||||
@@ -256,7 +278,6 @@ describe('dropdownToggle', function() {
|
||||
$rootScope.isopen = true;
|
||||
$rootScope.$digest();
|
||||
expect(isFocused(element.find('a'))).toBe(true);
|
||||
element.remove();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -396,7 +417,6 @@ describe('dropdownToggle', function() {
|
||||
triggerKeyDown($document, 27);
|
||||
expect(element.hasClass('open')).toBe(false);
|
||||
expect(isFocused(element.find('a'))).toBe(true);
|
||||
element.remove();
|
||||
});
|
||||
|
||||
it('should close anyway if another dropdown is opened', function() {
|
||||
|
||||
Reference in New Issue
Block a user