J'ai un menu déroulant Twitter Bootstrap. Comme le savent tous les utilisateurs de Twitter Bootstrap, le menu déroulant se ferme au clic (même en cliquant à l'intérieur).
Pour éviter cela, je peux facilement attacher un gestionnaire d’événements click dans le menu déroulant et ajouter simplement le fameux event.stopPropagation()
.
<ul class="nav navbar-nav">
<li class="dropdown mega-dropdown">
<a href="javascript:;" class="dropdown-toggle" data-toggle="dropdown">
<i class="fa fa-list-alt"></i> Menu item 1
<span class="fa fa-chevron-down pull-right"></span>
</a>
<ul class="dropdown-menu mega-dropdown-menu">
<li>
<div id="carousel" class="carousel slide" data-ride="carousel">
<ol class="carousel-indicators">
<li data-slide-to="0" data-target="#carousel"></li>
<li class="active" data-slide-to="1" data-target="#carousel"></li>
</ol>
<div class="carousel-inner">
<div class="item">
<img alt="" class="img-rounded" src="img1.jpg">
</div>
<div class="item active">
<img alt="" class="img-rounded" src="img2.jpg">
</div>
</div>
<a data-slide="prev" role="button" href="#carousel"
class="left carousel-control">
<span class="glyphicon glyphicon-chevron-left"></span>
</a>
<a data-slide="next" role="button" href="#carousel"
class="right carousel-control">
<span class="glyphicon glyphicon-chevron-right"></span>
</a>
</div>
</li>
</ul>
</li>
</ul>
Cela semble facile et très courant, cependant, et puisque les gestionnaires d'événements carousel-controls
(ainsi que carousel indicators
) sont délégués à l'objet document
, l'événement click
sur ces éléments (contrôles prev/next, ...) Etre ignoré".
$('ul.dropdown-menu.mega-dropdown-menu').on('click', function(event){
// The event won't be propagated up to the document NODE and
// therefore delegated events won't be fired
event.stopPropagation();
});
S'appuyant sur les listes déroulantes Bootstrap de Twitter hide
/hidden
n'est pas une solution pour les raisons suivantes:
flag
Ce violon est le comportement normal et ce violon est avec event.stopPropagation()
ajouté.
Merci à Roman pour sa réponse . J'ai aussi trouvé un réponse que vous pouvez trouver ci-dessous .
Supprimer l'attribut de données data-toggle="dropdown"
et implémenter l'ouverture/la fermeture du menu déroulant peut constituer une solution.
Commencez par cliquer sur le lien pour ouvrir/fermer le menu déroulant comme suit:
$('li.dropdown.mega-dropdown a').on('click', function (event) {
$(this).parent().toggleClass('open');
});
puis écoutez les clics en dehors du menu déroulant pour le fermer comme suit:
$('body').on('click', function (e) {
if (!$('li.dropdown.mega-dropdown').is(e.target)
&& $('li.dropdown.mega-dropdown').has(e.target).length === 0
&& $('.open').has(e.target).length === 0
) {
$('li.dropdown.mega-dropdown').removeClass('open');
}
});
Voici la démo: http://jsfiddle.net/RomaLefrancois/hh81rhcm/2/
Cela devrait aider aussi
$(document).on('click', 'someyourContainer .dropdown-menu', function (e) {
e.stopPropagation();
});
Bootstrap fournit la fonction suivante:
| Cet événement est déclenché immédiatement lorsque la méthode d'occurrence de masquage Hide.bs.dropdown | a été appelé. L'élément d'ancrage à bascule est disponible en tant que | relatedTarget propriété de l'événement.
Par conséquent, l'implémentation de cette fonction devrait pouvoir désactiver la fermeture du menu déroulant.
$('#myDropdown').on('hide.bs.dropdown', function (e) {
var target = $(e.target);
if(target.hasClass("keepopen") || target.parents(".keepopen").length){
return false; // returning false should stop the dropdown from hiding.
}else{
return true;
}
});
La meilleure solution consiste à placer une balise de formulaire après le menu déroulant de la classe.
alors votre code est
<ul class="dropdown-menu">
<form>
<li>
<div class="menu-item">bla bla bla</div>
</li>
</form>
</ul>
J'ai aussi trouvé une solution.
En supposant que les gestionnaires d'événements liés à Twitter Bootstrap Components
soient délégués à l'objet document
, je boucle les gestionnaires attachés et vérifie si l'élément sur lequel l'utilisateur a cliqué (ou l'un de ses parents) est concerné par un événement délégué.
$('ul.dropdown-menu.mega-dropdown-menu').on('click', function(event){
var events = $._data(document, 'events') || {};
events = events.click || [];
for(var i = 0; i < events.length; i++) {
if(events[i].selector) {
//Check if the clicked element matches the event selector
if($(event.target).is(events[i].selector)) {
events[i].handler.call(event.target, event);
}
// Check if any of the clicked element parents matches the
// delegated event selector (Emulating propagation)
$(event.target).parents(events[i].selector).each(function(){
events[i].handler.call(this, event);
});
}
}
event.stopPropagation(); //Always stop propagation
});
J'espère que cela aidera tout le monde à la recherche d'une solution similaire.
Merci à tous pour votre aide.
$('body').on("click", ".dropdown-menu", function (e) {
$(this).parent().is(".open") && e.stopPropagation();
});
Cela peut fonctionner pour toutes les conditions.
Cela pourrait aider:
$("dropdownmenuname").click(function(e){
e.stopPropagation();
})
jQuery:
<script>
$(document).on('click.bs.dropdown.data-api', '.dropdown.keep-inside-clicks-open', function (e) {
e.stopPropagation();
});
</script>
HTML:
<div class="dropdown keep-inside-clicks-open">
<button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">
Dropdown Example
<span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li><a href="#">HTML</a></li>
<li><a href="#">CSS</a></li>
<li><a href="#">JavaScript</a></li>
</ul>
</div>
Démo:
Générique: https://jsfiddle.net/kerryjohnson/omefq68b/1/
Votre démo avec cette solution: http://jsfiddle.net/kerryjohnson/80oLdtbf/101/
J'ai récemment eu un problème similaire et j'ai essayé différentes manières de le résoudre en supprimant l'attribut de données data-toggle="dropdown"
et en écoutant click
avec event.stopPropagation()
en appelant.
La deuxième façon semble plus préférable. Les développeurs Bootstrap utilisent également cette méthode . Dans le fichier source, j'ai trouvé l'initialisation des éléments déroulants:
// APPLY TO STANDARD DROPDOWN ELEMENTS
$(document)
.on('click.bs.dropdown.data-api', clearMenus)
.on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
.on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
.on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)
.on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown)
}(jQuery);
Donc, cette ligne:
.on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
suggère de placer un élément form
dans le conteneur avec la classe .dropdown
afin d'éviter de fermer le menu déroulant.
$('body').on("click", ".dropdown-menu", function (e) {
$(this).parent().is(".show") && e.stopPropagation();
});
cela fonctionne en 2018
$('ul.nav.navbar-nav').on('click.bs.dropdown', function(e){
var $a = $(e.target), is_a = $a.is('.is_a');
if($a.hasClass('dropdown-toggle')){
$('ul.dropdown-menu', this).toggle(!is_a);
$a.toggleClass('is_a', !is_a);
}
}).on('mouseleave', function(){
$('ul.dropdown-menu',this).hide();
$('.is_a', this).removeClass('is_a');
});
je l'ai mis à jour une fois de plus pour qu'il soit le plus intelligent et le plus fonctionnel possible. il se ferme maintenant lorsque vous survolez le navigateur, restant ouvert tant que vous y êtes. simplement parfait.
Avec Angular2 Bootstrap, vous pouvez utiliser nonInput pour la plupart des scénarios:
<div dropdown autoClose="nonInput">
nonInput - (valeur par défaut) ferme automatiquement la liste déroulante lorsque vous cliquez sur l'un de ses éléments - tant que l'élément sur lequel vous cliquez n'est pas une entrée ou une zone de texte.
Comme par exemple Bootstrap 4 Alpha a cet événement de menu. Pourquoi ne pas utiliser?
// PREVENT INSIDE MEGA DROPDOWN
$('.dropdown-menu').on("click.bs.dropdown", function (e) {
e.stopPropagation();
e.preventDefault();
});
Vous pouvez arrêter de cliquer sur le menu déroulant et ensuite réimplémenter manuellement les contrôles du carrousel à l’aide des méthodes javascript carousel .
$('ul.dropdown-menu.mega-dropdown-menu').on('click', function(event) {
event.stopPropagation();
});
$('a.left').click(function () {
$('#carousel').carousel('prev');
});
$('a.right').click(function () {
$('#carousel').carousel('next');
});
$('ol.carousel-indicators li').click(function (event) {
var index = $(this).data("slide-to");
$('#carousel').carousel(index);
});
Voici le jsfiddle .
Bootstrap a résolu ce problème lui-même en prenant en charge les balises <form>
dans les menus déroulants. Leur solution est assez simple et vous pouvez la lire ici: https://github.com/twbs/bootstrap/blob/v4-dev/js/src/dropdown.js
Cela se résume à empêcher la propagation au niveau de l'élément de document et ce, uniquement pour les événements de type 'click.bs.dropdown.data-api'
qui correspondent au sélecteur '.dropdown .your-custom-class-for-keep-open-on-click-elements'
.
Ou en code
$(document).on('click.bs.dropdown.data-api', '.dropdown .keep-open-on-click', (event) => {
event.stopPropagation();
});
Je sais que cette question était spécifiquement pour jQuery, mais pour toute personne utilisant ce problème avec AngularJS, vous pouvez créer une directive qui gère ceci:
angular.module('app').directive('dropdownPreventClose', function() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
element.on('click', function(e) {
e.stopPropagation(); //prevent the default behavior of closing the dropdown-menu
});
}
};
});
Ensuite, ajoutez simplement l'attribut dropdown-prevent-close
à votre élément qui déclenche la fermeture du menu. Cela devrait l'empêcher. Pour moi, c'était un élément select
qui fermait automatiquement le menu:
<div class="dropdown-menu">
<select dropdown-prevent-close name="myInput" id="myInput" ng-model="myModel">
<option value="">Select Me</option>
</select>
</div>
[Bootstrap 4 Alpha 6] [Rails] Pour le développeur Rails, e.stopPropagation()
conduira à un comportement indésirable pour link_to
avec data-method
différent de get
puisqu'il retournera par défaut toute votre demande sous la forme get
.
Pour remédier à ce problème, je suggère cette solution, qui est universelle
$('.dropdown .dropdown-menu').on('click.bs.dropdown', function() {
return $('.dropdown').one('hide.bs.dropdown', function() {
return false;
});
});
$('.dropdown .dropdown-menu').on('click.bs.dropdown', function() {
return $('.dropdown').one('hide.bs.dropdown', function() {
return false;
});
});
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.1.1.slim.min.js" integrity="sha384-A7FZj7v+d/sdmMqp/nOQwliLvUsJfDHW+k9Omg/a/EheAdgtzNs3hpfag6Ed950n" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js" integrity="sha384-DztdAPBWPRXSA/3eYEEUWrWCy7G5KFbe8fFjk5JAIxUYHKkDx6Qin1DkWx51bBrb" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js" integrity="sha384-vBWWzlZJ8ea9aCX4pEW3rVHjgjt7zpkNpZk+02D9phzyeVkE+jo0ieGizqPLForn" crossorigin="anonymous"></script>
<ul class="nav navbar-nav">
<li class="dropdown mega-dropdown">
<a href="javascript:;" class="dropdown-toggle" data-toggle="dropdown">
<i class="fa fa-list-alt"></i> Menu item 1
<span class="fa fa-chevron-down pull-right"></span>
</a>
<ul class="dropdown-menu mega-dropdown-menu">
<li>
<div id="carousel" class="carousel slide" data-ride="carousel">
<ol class="carousel-indicators">
<li data-slide-to="0" data-target="#carousel"></li>
<li class="active" data-slide-to="1" data-target="#carousel"></li>
</ol>
<div class="carousel-inner">
<div class="item">
<img alt="" class="img-rounded" src="img1.jpg">
</div>
<div class="item active">
<img alt="" class="img-rounded" src="img2.jpg">
</div>
</div>
<a data-slide="prev" role="button" href="#carousel" class="left carousel-control">
<span class="glyphicon glyphicon-chevron-left"></span>
</a>
<a data-slide="next" role="button" href="#carousel" class="right carousel-control">
<span class="glyphicon glyphicon-chevron-right"></span>
</a>
</div>
</li>
</ul>
</li>
</ul>
J'ai modifié la réponse de @ Vartan pour que cela fonctionne avec Bootstrap 4.3. Sa solution ne fonctionne plus avec la dernière version car la propriété target
renvoie toujours la racine div
de la liste déroulante, quel que soit l'endroit où le clic a été placé.
Voici le code:
$('.dropdown-keep-open').on('hide.bs.dropdown', function (e) {
if (!e.clickEvent) {
// There is no `clickEvent` property in the `e` object when the `button` (or any other trigger) is clicked.
// What we usually want to happen in such situations is to hide the dropdown so we let it hide.
return true;
}
var target = $(e.clickEvent.target);
return !(target.hasClass('dropdown-keep-open') || target.parents('.dropdown-keep-open').length);
});
<div class="dropdown dropdown-keep-open">
<button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Dropdown button
</button>
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
<a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<a class="dropdown-item" href="#">Something else here</a>
</div>
</div>
Dans le contenu .dropdown
, placez la classe .keep-open
sur n'importe quelle étiquette comme ceci:
$('.dropdown').on('click', function (e) {
var target = $(e.target);
var dropdown = target.closest('.dropdown');
if (target.hasClass('keep-open')) {
$(dropdown).addClass('keep-open');
} else {
$(dropdown).removeClass('keep-open');
}
});
$(document).on('hide.bs.dropdown', function (e) {
var target = $(e.target);
if ($(target).is('.keep-open')) {
return false
}
});
Les cas précédents évitaient les événements liés aux objets conteneur. Désormais, le conteneur hérite de la classe keep-open et check avant sa fermeture.
La solution de travail la plus simple pour moi est:
keep-open
à des éléments qui ne devraient pas causer la fermeture de la liste déroulante$('.dropdown').on('click', function(e) {
var target = $(e.target);
var dropdown = target.closest('.dropdown');
return !dropdown.hasClass('open') || !target.hasClass('keep-open');
});
Je sais qu’il existe déjà une réponse suggérant d’utiliser un formulaire, mais le balisage fourni n’est pas correct/idéal. Voici la solution la plus simple, aucun javascript nécessaire et cela ne casse pas votre liste déroulante. Fonctionne avec Bootstrap 4.
<form class="dropdown-item">
<!-- Your elements go here -->
</form>
J'ai trouvé qu'aucune des solutions ne fonctionnait comme j'aimerais utiliser la navigation bootstrap par défaut. Voici ma solution à ce problème:
$(document).on('hide.bs.dropdown', function (e) {
if ($(e.currentTarget.activeElement).hasClass('dropdown-toggle')) {
$(e.relatedTarget).parent().removeClass('open');
return true;
}
return false;
});
Au lieu d'écrire du code javascript ou jquery (réinventer la roue). Le scénario ci-dessus peut être géré par l'option de fermeture automatique du bootstrap . Vous pouvez fournir l'une des valeurs suivantes pour auto-close:
toujours - (valeur par défaut) ferme automatiquement la liste déroulante lorsque l'utilisateur clique sur l'un de ses éléments.
outsideClick - ferme automatiquement la liste déroulante uniquement lorsque l'utilisateur clique sur un élément ne figurant pas dans la liste déroulante.
disabled - désactive la fermeture automatique
Jetez un coup d'oeil au plunkr suivant:
http://plnkr.co/edit/gnU8M2fqlE0GscUQtCWa?p=preview
Ensemble
uib-dropdown auto-close="disabled"
J'espère que cela t'aides :)
Vous pouvez avoir des problèmes si vous utilisez la méthode return false ou stopPropagation (), car vos événements seront interrompus. Essayez ce code, ça marche très bien:
$(function() {
$('.dropdown').on("click", function (e) {
$('.keep-open').removeClass("show");
});
$('.dropdown-toggle').on("click", function () {
$('.keep-open').addClass("show");
});
$( ".closeDropdown" ).click(function() {
$('.dropdown').closeDropdown();
});
});
jQuery.fn.extend({
closeDropdown: function() {
this.addClass('show')
.removeClass("keep-open")
.click()
.addClass("keep-open");
}
});
En HTML:
<div class="dropdown keep-open" id="search-menu" >
<button class="btn dropdown-toggle btn btn-primary" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fa fa-filter fa-fw"></i>
</button>
<div class="dropdown-menu">
<button class="dropdown-item" id="opt1" type="button">Option 1</button>
<button class="dropdown-item" id="opt2" type="button">Option 2</button>
<button type="button" class="btn btn-primary closeDropdown">Close</button>
</div>
</div>
Si vous voulez fermer le dropdrown:
`$('#search-menu').closeDropdown();`
$(function() {
$('.mega-dropdown').on('hide.bs.dropdown', function(e) {
var $target = $(e.target);
return !($target.hasClass("keep-open") || $target.parents(".keep-open").size() > 0);
});
$('.mega-dropdown > ul.dropdown-menu').on('mouseenter', function() {
$(this).parent('li').addClass('keep-open')
}).on('mouseleave', function() {
$(this).parent('li').removeClass('keep-open')
});
});
Pour fermer la liste déroulante uniquement si un événement click a été déclenché en dehors de la liste déroulante d'amorçage, voici ce qui a fonctionné pour moi:
Fichier JS:
$('.createNewElement').on('click.bs.dropdown.data-api', '.tags-btn-group.keep-open-dropdown', function (e) {
var target = $(e.target);
if (target.hasClass("dropdown-menu") || target.parents(".dropdown-menu").length) {
e.stopPropagation();
}
});
Fichier HTML:
<!-- button: -->
<div class="createNewElement">
<div class="btn-group tags-btn-group keep-open-dropdown">
<div class="dropdown-toggle" data-toggle="dropdown" aria-expanded="false">OPEN DROPDOWN</div>
<ul class="dropdown-menu">
WHAT EVER YOU WANT HERE...
</ul>
</div>
</div>
Dans Bootstrap 4, vous pouvez également le faire:
$('#dd-link').on('hide.bs.dropdown', onListHide)
function onListHide(e)
{
if(e.clickEvent && $.contains(e.relatedTarget.parentNode, e.clickEvent.target)) {
e.preventDefault()
}
}
où #dd-link
est l'élément d'ancrage ou le bouton qui possède la propriété data-toggle="drowndown"
.
Vous devez ajouter "hold-on-click" à la classe "menu déroulant"
Je l'ai fait avec ceci:
$(element).on({
'mouseenter': function(event) {
$(event.currentTarget).data('mouseover', true);
},
'mouseleave': function(event) {
$(event.currentTarget).data('mouseover', false);
},
'hide.bs.dropdown': function (event) {
return !$(event.currentTarget).data('mouseover');
}
});
Cela m'a aidé
$('.dropdown-menu').on('click', function (e) {
if ($(this).parent().is(".open")) {
var target = $(e.target);
if (target.hasClass("keepopen") || target.parents(".keepopen").length){
return false;
}else{
return true;
}
}
});
Votre élément de menu déroulant doit ressembler à ceci (notez les classes dropdown-menu
et keepopen
.
<ul role="menu" class="dropdown-menu topmenu-menu eserv_top_notifications keepopen">
Le code ci-dessus empêche de miser sur le <body>
complet, mais sur l'élément specfic avec la classe dropdown-menu
.
J'espère que ça aide quelqu'un.
Merci.
Vous pouvez passer par le code ci-dessous pour résoudre ce problème.
$(document).on('click.bs.dropdown.data-api', '.keep_it_open', function (e) {
e.stopPropagation();
});
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/css/bootstrap.min.css" rel="stylesheet"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/js/bootstrap.min.js"></script>
<div class="dropdown keep_it_open">
<button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">Dropdown Example
<span class="caret"></span></button>
<ul class="dropdown-menu">
<li><a href="#">HTML</a></li>
<li><a href="#">CSS</a></li>
<li><a href="#">JavaScript</a></li>
</ul>
</div>