Évitez le menu déroulant fermez le clic à l'intérieur

310

J'ai un menu déroulant Twitter Bootstrap. Comme tous les utilisateurs de Twitter Bootstrap le savent, 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 de clic dans le menu déroulant et simplement ajouter le célèbre 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 un comportement très courant, cependant, et puisque carousel-controls(ainsi que carousel indicators) les gestionnaires d'événements sont délégués à l' documentobjet, l' clickévénement sur ces éléments ( contrôles prev / next , ...) sera "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'appuyer sur Twitter Bootstrap dropdown hide/ hiddenevents n'est pas une solution pour les raisons suivantes:

  • L'objet événement fourni pour les deux gestionnaires d'événements ne fait pas référence à l'élément cliqué
  • Je n'ai aucun contrôle sur le contenu du menu déroulant, il flagn'est donc pas possible d' ajouter une classe ou un attribut

Ce violon est le comportement normal et ce violon est event.stopPropagation()ajouté.

Mettre à jour

Merci à Roman pour sa réponse . J'ai également trouvé une réponse que vous pouvez trouver ci-dessous .

php-dev
la source
1. Votre jsfiddle ne fonctionne pas. 2. Que voulez-vous exactement réaliser?
paulalexandru
1
@paulalexandru, mis à jour, a ajouté deux violons. Un comportement par défaut et un avec modification. Essayez de cliquer sur le bouton suivant et précédent, ou sur les indicateurs. Pour le premier exemple, le menu se cache et les diapositives du carrousel. ou le deuxième exemple: le menu reste ouvert, mais le carrousel n'a pas glissé depuis l' event propagationarrêt du.
php-dev
@paulalexandru Compris, non?
php-dev
@ php-dev: je l'ai mis à jour à nouveau pour relever le défi, maintenant c'est parfait ... voir la démo.
Luca Filosofi

Réponses:

373

La suppression de l'attribut de données data-toggle="dropdown"et l'implémentation de l'ouverture / fermeture de la liste déroulante peuvent être une solution.

Commencez par cliquer sur le lien pour ouvrir / fermer la liste déroulante comme ceci:

$('li.dropdown.mega-dropdown a').on('click', function (event) {
    $(this).parent().toggleClass('open');
});

puis en écoutant les clics en dehors de la liste déroulante pour la fermer comme ceci:

$('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/

Roma
la source
2
Cette solution fonctionne bien. La prime devrait vous être attribuée s'il n'y a pas d'autre réponse.
php-dev
1
Votre solution est fonctionnelle, générique et également «populaire». La prime devrait être attribuée à votre réponse. J'ai également trouvé une réponse, regardez-la ci-dessous;)
php-dev
1
@Cichy ... modifiez simplement le premier gestionnaire comme ceci ... $ ('li.dropdown.mega-dropdown a'). On ('click', fonction (event) {$ ('li.dropdown.mega-dropdown .open '). removeClass (' open '); $ (this) .parent (). toggleClass (' open ');});
dsaket
63
Cette réponse préférée est un hack. sensationnel!!! Voici une réponse BOOTSTRAP 4 ALPHA plus simple pour éviter les clics internes dans une méga-liste déroulante. // PREVENT INSIDE CLICK DROPDOWN $('.dropdown-menu').on("click.bs.dropdown", function (e) { e.stopPropagation(); e.preventDefault(); });
Frank Thoeny
7
e.stopPropagation()est la meilleure solution.
nacholibre
332

Cela devrait aussi aider

$(document).on('click', 'someyourContainer .dropdown-menu', function (e) {
  e.stopPropagation();
});
Arbejdsglæde
la source
33
Je pense que c'est à coup sûr la solution la plus simple à ce problème. Bravo - venez de tester celui-ci et ça marche!
Torsten Barthel
13
C'est de loin la meilleure solution.
silencieux
3
C'est la solution la plus courante, mais j'ai une exigence différente. Veuillez lire attentivement ma question :)
php-dev
4
Meilleure solution pour simplement garder le menu ouvert sur les clics.
Matt Pierce
2
La meilleure solution en effet. Personnellement, j'ai utilisé '.dropdown-menu :not(.dropdown-item)'pour que cliquer sur un dropdown-itemferme la fenêtre contextuelle, mais pas sur un dropdown-header.
Benjamin
41

Bootstrap fournit la fonction suivante:

                 | Cet événement est déclenché immédiatement lorsque la méthode de masquage de l'instance
hide.bs.dropdown | a été appelé. L'élément d'ancrage à bascule est disponible en tant que
                 | propriété relatedTarget de l'événement.

Par conséquent, la mise en œuvre de cette fonction devrait être en mesure de désactiver la fermeture de la liste déroulante.

$('#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;
    }
});
Vartan
la source
2
@Vartan, la targetpropriété de l'événement est également la li.dropdown, la relatedTargetest la a.dropdown-toggle. Vous ne pouvez donc pas faire référence à l'élément cliqué dans le hidegestionnaire d'événements.
php-dev du
2
hasClass prend un nom de classe, pas un sélecteur CSS. target.hasClass(".keepopen")devrait être target.hasClass("keepopen"). Sinon, le code ne fonctionnera pas.
Hugh Guiney
3
J'ai scanné Internet et c'est de loin la solution la plus intelligente, pour cette raison ... msot d'autres méthodes appellent une approche qui utilise l'arrêt de l'événement par défaut ou l'arrêt de la propagation. ces approches sont très mauvaises car elles briseront tout autre événement déclenché à l'intérieur de la liste déroulante (c'est-à-dire mes éléments de formulaire mobile jquery) en utilisant cette approche vous permet d'identifier spécifiquement quand le menu lui-même se ferme et vous permet d'agir sur cet événement seul. cette réponse a besoin de tant d'étoiles ....
webfish
3
@webfish Combien vous a-t-il fallu pour numériser Internet? (rofl)
php-dev
2
Peut-être que cela fonctionnait .. mais avec bootstrap 4, e.target est toujours la liste déroulante elle-même. Pas la cible cliquée. Même si vous cliquez en dehors des listes déroulantes, e.target est toujours la liste déroulante. Vous ne pouvez donc pas effectuer ce type de vérification. Quelqu'un voit un moyen de contourner cela?
FredArters
36

La meilleure réponse absolue est de mettre une balise de formulaire après le menu déroulant de la classe

donc votre code est

<ul class="dropdown-menu">
  <form>
    <li>
      <div class="menu-item">bla bla bla</div>
    </li>
  </form>
</ul>
Gregory Bowers
la source
2
fonctionnellement a fonctionné magnifiquement pour moi, mais a cassé le style
2778
2
ce fut la solution la plus rapide pour moi
Jonathan Morales Vélez
15
Ce n'est pas une meilleure réponse :) un <li>élément ne doit pas être à l'intérieur d'un <form> élément.
GETah
2
Ce n'est pas une solution sémantiquement correcte - le seul enfant valide d'un UL est un LI - si quelque chose les balises de formulaire doivent être à l'intérieur des balises li - mais cela peut ne pas permettre l'action souhaitée - de toute façon un ul> formulaire> li n'est pas balisage correct
gavgrif
2
Thnaks pour cette solution rapide
Herman Demsong
27

J'ai également trouvé une solution.

En supposant que les Twitter Bootstrap Componentsgestionnaires d'événements associés sont délégués à l' documentobjet, je boucle les gestionnaires attachés et vérifie si l'élément cliqué actuel (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 aide toute personne à la recherche d'une solution similaire.

Merci à tous pour votre aide.

php-dev
la source
1
Sensationnel!!! a parfaitement fonctionné! A eu des ennuis pendant une semaine, j'utilise mCustomeScrollbar et après avoir cliqué sur la barre de défilement dans le menu déroulant, il le fermait, votre script a fonctionné et maintenant son fonctionne bien! Mille mercis.
eirenaios
fonctionne très bien! comment étendre cela, afin qu'un utilisateur puisse toujours appuyer sur "ESC" (ou même cliquer à l'extérieur) sur le clavier pour fermer le DD?
Oncle Iroh
2
@MaggewDotCom La pression sur la touche ESC devrait toujours fonctionner. La même chose pour cliquer à l'extérieur ...
php-dev
Le seul inconvénient de cette solution est qu'elle n'autorise pas les listes déroulantes imbriquées (supposons que vous ayez un droit dans une liste déroulante). Existe-t-il une solution de contournement pour ce cas?
sdvnksv
26

Cela pourrait aider:

$("dropdownmenuname").click(function(e){
   e.stopPropagation();
})
Bawantha
la source
C'est certainement la réponse la plus simple / la meilleure si vous voulez qu'un utilisateur interagisse avec un élément d'interface utilisateur présent dans la liste déroulante (par exemple les boutons radio) et que vous ne voulez pas que le menu se ferme lorsqu'il bascule entre les options.
Rob
22
$('body').on("click", ".dropdown-menu", function (e) {
    $(this).parent().is(".open") && e.stopPropagation();
});

Cela peut fonctionner pour toutes les conditions.

Terry Lin
la source
cela devrait être la bonne réponse car elle utilise moins de lignes de code plutôt que la réponse sélectionnée
Muhammad Omer Aslam
@MuhammadOmerAslam Nah! Comme il ne répond pas à mes exigences
php-dev
12

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/

Kerry Johnson
la source
9

J'ai essayé cette chose simple et cela a fonctionné comme un charme.

J'ai changé le menu déroulant élément de <div>la <form>et cela a bien fonctionné.

<div class="nav-item dropdown" >
  <a href="javascript:;" class="nav-link dropdown-toggle" data-toggle="dropdown">
   Click to open dropdown
 </a>
 <form class="dropdown-menu   ">
  <ul class="list-group text-black">
     <li class="list-group-item"  >
     </li>
     <li class="list-group-item"   >
     </li>
  </ul>
</form>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>

<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"></script>


<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet"/>


<div class="nav-item dropdown" >
  <a href="javascript:;" class="nav-link dropdown-toggle" data-toggle="dropdown">
   Click to open dropdown
 </a>
 <form class="dropdown-menu   ">
  <ul class="list-group text-black">
     <li class="list-group-item"  >
      List Item 1
     </li>
     <li class="list-group-item"   >
         LI 2<input class="form-control" />
     </li>
     <li class="list-group-item"   >
        List Item 3
     </li>
  </ul>
</form>

TheVigilant
la source
6

J'ai récemment rencontré un problème similaire et j'ai essayé différentes façons de le résoudre en supprimant l'attribut de données data-toggle="dropdown"et en écoutant clickavecevent.stopPropagation() l' appel.

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 que vous puissiez mettre un formélément à l'intérieur du conteneur avec la classe .dropdownpour éviter de fermer le menu déroulant.

Il y a
la source
6

Bootstrap a résolu ce problème lui-même en prenant en charge les <form>balises dans les listes déroulantes. Leur solution est assez compréhensible et vous pouvez la lire ici: https://github.com/twbs/bootstrap/blob/v4-dev/js/src/dropdown.js

Cela revient à empêcher la propagation au niveau de l'élément de document et à le faire uniquement pour les événements de type 'click.bs.dropdown.data-api'correspondant 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();
});
Daniel Schlaug
la source
1
Merci merci merci pour le lien vers la source. Pour d'autres qui se demandent pourquoi l' formapproche des exemples ne fonctionne pas pour vous - j'utilisais la classe dropleft, mais elle a également besoin dropdownpour que le sélecteur de formulaire corresponde.
Mark K Cowan
6

J'ai modifié la réponse de @ Vartan pour la faire fonctionner avec Bootstrap 4.3. Sa solution ne fonctionne plus avec la dernière version car la targetpropriété retourne toujours la racine de la liste déroulantediv peu importe 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>
Konrad Kalemba
la source
en ligne:$('.dropdown-keep-open').on('hide.bs.dropdown', ev => !(ev.clickEvent && $(ev.target).has(ev.clickEvent.target).length))
Matveev Dmitriy
@MatveevDmitriy Je suis désolé, mais personne, tout simplement personne ne peut lire ce document. Écrire du code de cette façon est une mauvaise pratique.
ViRuSTriNiTé
La dernière ligne peut être simplifiée à l'aide de return !target.closest('.dropdown-keep-open').length). Cela dit, c'est une excellente solution! Trouvé cela nécessaire pour résoudre ce problème.
patrick3853
6
$('body').on("click", ".dropdown-menu", function (e) {
    $(this).parent().is(".show") && e.stopPropagation();
});
waza123
la source
Tout d'abord, merci pour votre réponse. La question est déjà répondue. De plus, j'ai une exigence différente de celle décrite dans la question par rapport à l'exigence courante.
php-dev
4
$('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 pour être le plus intelligent et le plus fonctionnel possible. il se ferme maintenant lorsque vous survolez le nav, en restant ouvert pendant que vous y êtes. simplement parfait.

Luca Filosofi
la source
Votre solution est intelligente en raison de sa brièveté, cependant, après avoir ajouté la classe show, la liste déroulante ne se ferme pas lorsque vous cliquez à l'extérieur, et nous devons cliquer sur le bouton déroulant avant ... +1 quand même
php-dev
je l'ai mis à jour, regardez la démo. c'est la meilleure cause de ne pas vérifier à chaque fois l'événement de clic de corps. n'affecte que les éléments à l'intérieur de chaque élément nav, pas à l'extérieur.
Luca Filosofi
Ma solution ne dépend pas non plus de l' bodyévénement click ^^
php-dev
oui, il relaie en partie l'événement de clic de corps, il essaie de vérifier quel élément a été cliqué à travers la délégation de corps. $('body').on('click', function (e) {
Luca Filosofi
Non! Ce n'est pas ma réponse. Ma réponse est la dernière publiée.
php-dev
4

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();                
});
Frank Thoeny
la source
1
e.preventDefault();bloque les liens, vous pouvez l'ignorer
long
@czachor vous avez raison! e.preventDefault (); Empêcher un lien de suivre l'URL.
Frank Thoeny
3

Vous pouvez arrêter de cliquer sur la liste déroulante de la propagation, puis réimplémenter manuellement les contrôles du carrousel à l'aide des méthodes javascript du carrousel .

$('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 .

Neil
la source
Votre exemple fonctionne bien mais le problème est que la liste déroulante peut contenir n'importe quel contenu et pas seulement des images carrousel ...
php-dev
3

Avec Angular2 Bootstrap, vous pouvez utiliser nonInput pour la plupart des scénarios:

<div dropdown autoClose="nonInput">

nonInput - (par défaut) ferme automatiquement la liste déroulante lorsque l'un de ses éléments est cliqué - tant que l'élément cliqué n'est pas une entrée ou une zone de texte.

https://valor-software.com/ng2-bootstrap/#/dropdowns

Nir Soudry
la source
2

Je sais que cette question était spécifiquement pour jQuery, mais pour toute personne utilisant AngularJS qui a ce problème, 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, et cela devrait l'empêcher. Pour moi, c'était un selectélément 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>
jtate
la source
6
<div class="dropdown-menu" ng-click="$event.stopPropagation()">fonctionne pour moi en 1.2.x
dr3w
2

[Bootstrap 4 Alpha 6] [Rails] Pour le développeur de rails, e.stopPropagation()conduira à un comportement indésirable pour link_toavec différent data-methodde getcar il retournera par défaut toute votre demande commeget .

Pour remédier à ce problème, je propose cette solution, universelle

$('.dropdown .dropdown-menu').on('click.bs.dropdown', function() {
  return $('.dropdown').one('hide.bs.dropdown', function() {
    return false;
  });
});

Jacky Tong
la source
2

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 de l'amorçage. Vous pouvez fournir l'une des valeurs à fermer automatiquement :

  1. toujours - (par défaut) ferme automatiquement la liste déroulante lorsque l'un de ses éléments est cliqué.

  2. outsideClick - ferme automatiquement la liste déroulante uniquement lorsque l'utilisateur clique sur un élément en dehors de la liste déroulante.

  3. désactivé - désactive la fermeture automatique

Jetez un œil au plunkr suivant:

http://plnkr.co/edit/gnU8M2fqlE0GscUQtCWa?p=preview

Ensemble

uib-dropdown auto-close="disabled" 

J'espère que cela t'aides :)

ashwaniKumar
la source
5
Il convient de noter explicitement que cela n'est bon que pour les utilisateurs ui-bootstrap, ce qui n'est probablement pas le cas pour de nombreuses personnes qui consultent cette question.
kevlarr
Vous avez bien décrit mais je pense que vous devriez écrire la solution comme uib-dropdown auto-close="outsideClick". Le menu fermé au clic à l'intérieur est juste un peu inconfortable mais le menu ne se ferme pas au clic à l'extérieur est assez bouleversant.
vusan
2

Je sais qu'il existe déjà une réponse précédente 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'est nécessaire et cela ne rompt pas votre liste déroulante. Fonctionne avec Bootstrap 4.

<form class="dropdown-item"> <!-- Your elements go here --> </form>

Radu Ciobanu
la source
@RosdiKasim Je le fais fonctionner correctement sur un site Web avec Bootstrap 4.0.0. Non testé avec 4.1
Radu Ciobanu
En fait, cela devrait ressembler à: <form class = "dropdown dropdown-item">
Nasser Sadraee
2

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 être comme ceci, (prenez note des classes dropdown-menuet keepopen.

<ul role="menu" class="dropdown-menu topmenu-menu eserv_top_notifications keepopen">

Le code ci-dessus empêche d'enchérir sur l'ensemble <body>, à la place de l'élément specfic avec la classedropdown-menu .

J'espère que cela aide quelqu'un.

Merci.

Anjana Silva
la source
Remerciements mis à jour selon Bootstrap 4 $ ('. Menu déroulant [data-managedropdownclose = "true"]'). On ('click', fonction (e) {if ($ (this) .parent (). Is ("" .show ")) {var target = $ (e.target); return (target.hasClass (" CloseDropDown ") || target.parents (". CloseDropDown "). length);}});
Thulasiram
1

La solution de travail la plus simple pour moi est:

  • ajout de keep-openclasse aux éléments qui ne devraient pas entraîner de fermeture de la liste déroulante
  • et ce morceau de code fait le reste:
$('.dropdown').on('click', function(e) {
    var target = $(e.target);
    var dropdown = target.closest('.dropdown');
    return !dropdown.hasClass('open') || !target.hasClass('keep-open');
});
Gee-Bee
la source
pouvez-vous m'aider à corriger ce stackoverflow.com/questions/51552712/… @ Gee-Bee
Zhu
1

Je n'ai trouvé aucune des solutions qui fonctionnait comme j'aimerais utiliser la navigation par défaut bootstrap. 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;
       });
Mike
la source
1

Dans le .dropdowncontenu, mettez la .keep-openclasse 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 conteneurs, maintenant le conteneur hérite de la classe keep-open et check avant d'être fermé.

Dixán Santiesteban Feria
la source
1

Je l'ai fait avec ça:

$(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');
    }
});
William
la source
0
$(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')
    });
});
SNC
la source
0

Pour fermer la liste déroulante uniquement si un événement de clic a été déclenché en dehors de la liste déroulante de bootstrap, 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>
Dudi
la source
0

Vous pouvez rencontrer des problèmes si vous utilisez la méthode return false ou stopPropagation () car vos événements seront interrompus. Essayez ce code, il fonctionne 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 souhaitez fermer le menu déroulant:

`$('#search-menu').closeDropdown();`
Hchab
la source
0

Dans Bootstrap 4, vous pouvez également faire ceci:

$('#dd-link').on('hide.bs.dropdown', onListHide)

function onListHide(e)
{
  if(e.clickEvent && $.contains(e.relatedTarget.parentNode, e.clickEvent.target)) {
  e.preventDefault()
  }
}

#dd-linkest l'élément d'ancrage ou le bouton qui a la data-toggle="drowndown"propriété.

Daniel
la source