Reputation: 747
I am using the Angular-Bootstrap Dropdown. I want to prevent it from closing on click until the user closes it intentionally.
Default state is: The Dropdown closes when clicking somewhere in the Document.
I identified the relevant lines of code: (Line 12, dropdown.js)
this.open = function( dropdownScope ) {
if ( !openScope ) {
$document.bind('click', closeDropdown); // line to unbind
$document.bind('keydown', escapeKeyBind);
}
}
You can find the full code here: Link to Github
I don't want to change the original sources of angular-bootstrap to keep my project open for updates.
My question:
How can i unbind an event bound by a Directive to the document in an Angular Controller?
Upvotes: 41
Views: 55288
Reputation: 158
You can stop event from bubbling up in DOM Tree in angular 2 and above by adding event propagation. Ex: (click)="$event.stopPropagation()"
Upvotes: 4
Reputation: 1102
Here is what the code looks like using the approved angular-bootstrap auto-close method. Notice the auto-close attribute goes on the top <div>
.
<div class="btn-group" uib-dropdown auto-close="disabled">
<button id="single-button" type="button" class="btn btn-primary" uib-dropdown-toggle>
Button dropdown <span class="caret"></span>
</button>
<ul class="dropdown-menu" uib-dropdown-menu role="menu" aria-labelledby="single-button">
<textarea class="form-control" ng-model="description" rows="4" placeholder="Description"></textarea>
</ul>
</div>
Upvotes: 0
Reputation: 576
For those who are using Angular UI-Bootstrap 0.13.0 or later version, here is the cleaner way that states on the UI-Bootstrap documentation.
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. The dropdown will no longer close on $locationChangeSuccess events.
Here is the link to the documentation: https://angular-ui.github.io/bootstrap/#/dropdown
Upvotes: 27
Reputation: 2786
You can decorate directives.
With this way you don't have to touch the original code and you can keep the original behaviour.
You can put a close button inside the dropdown
HTML
<div class="dropdown-menu keep-dropdown-open-on-click" role="menu">
<i class="icon-close close-dropdown-on-click"></i>
</div>
JS
angular.module('app').config(uiDropdownMenuDecorate);
uiDropdownMenuDecorate.$inject = ['$provide'];
function uiDropdownMenuDecorate($provide) {
$provide.decorator('dropdownMenuDirective', uiDropdownMenuDecorator);
uiDropdownMenuDecorator.$inject = ['$delegate'];
function uiDropdownMenuDecorator($delegate) {
var directive = $delegate[0];
var link = directive.link;
directive.compile = function () {
return function (scope, elem, attrs, ctrl) {
link.apply(this, [scope, elem, attrs, ctrl]);
elem.click(function (e) {
if (elem.hasClass('keep-dropdown-open-on-click') && !angular.element(e.target).hasClass('close-dropdown-on-click')) {
e.stopPropagation();
}
});
};
};
return $delegate;
}
}
Upvotes: 0
Reputation: 217
You can also use this solution : https://gist.github.com/Xspirits/684beb66e2499c3ff0e5 Gives you a bit more of control over the dropdown, if that's ever needed.
Upvotes: 0
Reputation: 1511
I solved this by adding the following to my drop down-menu. This prevents the drop down from closing unless you click on the tag that opens it
<ul class="dropdown-menu" ng-click="$event.stopPropagation()">
Upvotes: 149
Reputation: 1157
This is another hack, but you could add a directive to stop the toggle event from propagating. For example something like this worked for my specific use case:
<div>
<div class="btn-group" dropdown is-open="status.isopen" ng-controller="DropDownCtrl">
<button type="button" class="btn btn-primary dropdown-toggle" ng-disabled="disabled">
Button dropdown <span class="caret"></span>
</button>
<ul class="dropdown-menu" role="menu">
<li ng-click="goToPage('Action')">Action</li>
<li disable-auto-close>Don't Dismiss</li>
<li ng-click="goToPage('SomethingElse')">Something else here</li>
</ul>
</div>
Adding this directive to an element should disable the auto close behavior:
angular.module('plunker', ['ui.bootstrap'])
.controller('DropDownCtrl', ['$scope', '$location',
function($scope, $location) {
// Controller logic here
$scope.goToPage = function(page) {
console.log("Going to " + page + ". Dropdown should close");
$location.path(page);
};
}])
.directive('disableAutoClose', function() {
// directive for disabling the default
// close on 'click' behavior
return {
link: function($scope, $element) {
$element.on('click', function($event) {
console.log("Dropdown should not close");
$event.stopPropagation();
});
}
};
});
Upvotes: 3
Reputation: 656
This is an even more crude way of overriding it based on Rob Jacobs answer except that it prevents the ugly flickering ulilcht commented on:
$scope.toggled = function (open) {
$scope.open = true;
var child = $scope.$$childHead;
while (child) {
if (child.focusToggleElement) {
child.isOpen = true;
break;
}
child = child.$$nextSibling;
}
};
Upvotes: 0
Reputation: 6629
This is a crude way of overriding it. You need to control the is-open attribute manually and hijack the on-toggle event, example:
<div class="btn-group" dropdown is-open="ctrl.isOpen" on-toggle="toggled(open)">
<button type="button" class="btn btn-primary dropdown-toggle">
Button dropdown <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>
Controller:
$scope.toggled = function (open) {
$timeout(function () {
$scope.ctrl.isOpen = true;
});
};
I would ask for a property on the dropdownConfig constant (something like autoClose) for a permanent solution.
Upvotes: 0