J'utilise le menu déroulant Angular-Bootstrap. Je veux l'empêcher de se fermer en cliquant jusqu'à ce que l'utilisateur le ferme intentionnellement.
L'état par défaut est: La liste déroulante se ferme lorsque vous cliquez quelque part dans le document.
J'ai identifié les lignes de code pertinentes: (ligne 12, dropdown.js)
this.open = function( dropdownScope ) {
if ( !openScope ) {
$document.bind('click', closeDropdown); // line to unbind
$document.bind('keydown', escapeKeyBind);
}
}
Vous pouvez trouver le code complet ici: Lien vers Github
Je ne veux pas changer les sources originales de bootstrap angulaire pour garder mon projet ouvert aux mises à jour.
Ma question:
Comment puis-je dissocier un événement lié par une directive au document dans un contrôleur Angular?
J'ai résolu cela en ajoutant ce qui suit à mon menu déroulant. Cela empêche la liste déroulante de se fermer à moins que vous ne cliquiez sur la balise qui l'ouvre
<ul class="dropdown-menu" ng-click="$event.stopPropagation()">
Pour ceux qui utilisent Angular UI-Bootstrap 0.13.0 ou une version ultérieure, voici la manière la plus propre qui se trouve dans la documentation UI-Bootstrap.
Par défaut, la liste déroulante se fermera automatiquement si l'un de ses éléments est cliqué, vous pouvez modifier ce comportement en définissant l'option de fermeture automatique comme suit:
toujours par défaut) ferme automatiquement la liste déroulante lorsque l'un de ses éléments est cliqué.
outsideClick - ferme automatiquement la liste déroulante uniquement lorsque l'utilisateur clique sur un élément en dehors de la liste déroulante.
désactivé - désactive la fermeture automatique. Vous pouvez ensuite contrôler manuellement l'état d'ouverture/fermeture de la liste déroulante, en utilisant is-open. Veuillez noter que la liste déroulante se fermera toujours si vous cliquez sur la bascule, si vous appuyez sur la touche Échap ou si une autre liste déroulante est ouverte. La liste déroulante ne se fermera plus sur les événements $ locationChangeSuccess.
Voici le lien vers la documentation: --- (https://angular-ui.github.io/bootstrap/#/dropdown
Il s'agit d'un autre hack, mais vous pouvez ajouter une directive pour empêcher la propagation de l'événement bascule. Par exemple, quelque chose comme ça a fonctionné pour mon cas d'utilisation spécifique:
<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>
L'ajout de cette directive à un élément devrait désactiver le comportement de fermeture automatique:
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();
});
}
};
});
Vous pouvez empêcher l'événement de se propager dans l'arborescence DOM dans angular 2 et au-dessus en ajoutant la propagation d'événement. Ex: (click) = "$ event.stopPropagation ()"
Voici à quoi ressemble le code en utilisant la méthode de fermeture automatique angular-bootstrap approuvée. Notez que l'attribut de fermeture automatique va en haut <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>
C'est une façon encore plus grossière de la contourner basée sur la réponse de Rob Jacobs, sauf qu'elle empêche le vilain ulilcht vacillant commenté:
$scope.toggled = function (open) {
$scope.open = true;
var child = $scope.$$childHead;
while (child) {
if (child.focusToggleElement) {
child.isOpen = true;
break;
}
child = child.$$nextSibling;
}
};
C'est une façon grossière de la contourner. Vous devez contrôler l'attribut is-open manuellement et détourner l'événement on-toggle, exemple:
<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>
Manette:
$scope.toggled = function (open) {
$timeout(function () {
$scope.ctrl.isOpen = true;
});
};
Je demanderais une propriété sur la constante dropdownConfig (quelque chose comme autoClose) pour une solution permanente.
Vous pouvez également utiliser cette solution: https://Gist.github.com/Xspirits/684beb66e2499c3ff0e5 vous donne un peu plus de contrôle sur la liste déroulante, si cela est nécessaire.
Vous pouvez décorer des directives.
De cette façon, vous n'avez pas à toucher le code d'origine et vous pouvez conserver le comportement d'origine.
Vous pouvez mettre un bouton de fermeture dans la liste déroulante
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;
}
}