Éviter menu déroulant fermer sur Cliquez à l'intérieur

J'ai un menu déroulant Twitter Bootstrap. Comme tous les utilisateurs de Twitter Bootstrap le savent, le menu déroulant se ferme sur le clic (même en cliquant à l'intérieur).

Pour éviter cela, je peux facilement attacher un gestionnaire d'événement click dans le menu déroulant et simplement ajouter 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 un comportement très commun, cependant, et puisque carousel-controls (ainsi que carousel indicators) les gestionnaires d'événements sont délégués à l'objet document, l'événement click sur ces éléments (précédent / suivant contrôle, ...) 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'Appuyant sur Twitter Bootstrap déroulante hide/hidden les événements n'est pas une solution pour les raisons suivantes:

  • l'événement fourni pour les deux gestionnaires d'événements ne vous donne pas de référence à l'élément cliqué
  • le contenu du menu déroulant est généré dynamiquement, donc l'ajout d'une classe flag n'est pas possible

Ce violon est le comportement normal et ce violon est avec event.stopPropagation() ajouter.

Mise à jour

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

217
demandé sur Xufox 2014-08-02 01:59:07

24 réponses

Supprimer l'attribut de données data-toggle="dropdown" et implémenter l'ouverture / fermeture de la liste déroulante peut être une solution.

D'abord en manipulant le clic 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');
});

Et puis en écoutant les clics en dehors de la liste déroulante pour le 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/

302
répondu Roma 2015-02-09 00:12:47

Cela devrait aussi aider

$(document).on('click', 'someyourContainer .dropdown-menu', function (e) {
  e.stopPropagation();
});
226
répondu Arbejdsglæde 2016-06-02 15:38:37

Bootstrap donne la fonction suivante:

                 | This event is fired immediately when the hide instance method 
hide.bs.dropdown | has been called. The toggling anchor element is available as the 
                 | relatedTarget property of the event.

Par conséquent, l'implémentation de cette fonction devrait pouvoir désactiver la liste déroulante de la fermeture.

$('#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;
    }
});
30
répondu Vartan 2015-01-27 02:35:45

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

Donc votre code est

<ul class="dropdown-menu">
  <form>
    <li>
      <div class="menu-item">bla bla bla</div>
    </li>
  </form>
</ul>
23
répondu user3287193 2015-12-11 04:43:08

J'ai aussi trouvé une solution.

En supposant que les gestionnaires d'événements liés à Twitter Bootstrap Components sont délégués à l'objet document, je boucle les gestionnaires attachés et vérifie si l'élément cliqué en cours (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 quelqu'un à la recherche d'une solution similaire.

Merci à tous pour votre aide.

22
répondu php-dev 2015-02-12 22:11:40
$('body').on("click", ".dropdown-menu", function (e) {
    $(this).parent().is(".open") && e.stopPropagation();
});

Cela peut fonctionner pour toutes les conditions.

18
répondu Terry Lin 2016-12-04 13:51:22

Cela pourrait aider:

$("dropdownmenuname").click(function(e){
   e.stopPropagation();
})
11
répondu Bawantha 2018-04-20 00:02:06

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/

6
répondu Kerry Johnson 2017-04-21 19:56:54
$('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 être le plus intelligent et fonctionnel possible. il se ferme maintenant lorsque vous survolez à l'extérieur du nav, restant ouvert pendant que vous êtes à l'intérieur. tout simplement parfait.

4
répondu Luca Filosofi 2014-08-12 08:49:30

J'ai récemment eu 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 click avec event.stopPropagation() appelant.

La deuxième façon semble plus préférable. Aussi les développeurs Bootstrap utilisent de cette façon. 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 pouvez mettre un élément form dans le conteneur avec la classe .dropdown pour éviter de fermer le menu déroulant.

4
répondu Илья Баранов 2016-01-08 16:42:59

Vous pouvez arrêter de cliquer sur la liste déroulante de la propagation, puis réimplémenter manuellement les contrôles carrousel en utilisant méthodes JavaScript 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);
});

Est Ici le jsfiddle.

3
répondu Neil 2014-08-11 19:56:03

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

3
répondu Nir Soudry 2016-08-15 07:13:23

Comme par exemple Bootstrap 4 Alpha a cet événement de Menu. Pourquoi ne pas l'utiliser?

// PREVENT INSIDE MEGA DROPDOWN
$('.dropdown-menu').on("click.bs.dropdown", function (e) {
    e.stopPropagation();
    e.preventDefault();                
});
2
répondu Frank Thoeny 2016-03-29 03:55:41

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 é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>
2
répondu jtate 2016-06-14 16:26:33

[Bootstrap 4 Alpha 6] [Rails] Pour le développeur rails, e.stopPropagation() conduira à un comportement indésirable pour link_to avec data-method pas égal à get car il retournera par défaut toute votre requête comme 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>
2
répondu Jacky Tong 2017-03-29 07:53:45

La solution de travail la plus simple pour moi est:

  • ajout de la classe keep-open aux éléments qui ne devraient pas provoquer la 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');
});
1
répondu Gee-Bee 2016-07-14 11:25:25

J'ai trouvé qu'aucune des solutions ne fonctionnait comme je voudrais utiliser le nav 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;
       });
1
répondu Mike 2017-01-03 23:14:28

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 bootstrap. Vous pouvez fournir l'une des valeurs à Auto-close :

  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 l'auto fermer

Jetez un oeil à ce qui suit plunkr:

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

Ensemble

uib-dropdown auto-close="disabled" 

J'espère que cela aide :)

1
répondu ashwaniKumar 2017-06-07 11:03:06

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

1
répondu Dixán Santiesteban Feria 2017-09-06 13:39:31

Je sais qu'il y a 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, pas besoin de javascript et cela ne casse pas votre liste déroulante. Fonctionne avec Bootstrap 4.

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

1
répondu Radu Ciobanu 2018-03-18 07:29:27
$('body').on("click", ".dropdown-menu", function (e) {
    $(this).parent().is(".show") && e.stopPropagation();
});

Cela fonctionne en 2018

1
répondu waza123 2018-07-29 14:02:36
$(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')
    });
});
0
répondu SNC 2016-03-04 15:57:30

Pour fermer la liste déroulante uniquement si un événement de clic a été déclenché en dehors de la liste déroulante bootstrap, c'est 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>
0
répondu Dudi 2017-12-28 16:02:21
$(function() {
var closeble = false;
$('body').on('click', function (e) {
    if (!$(event.target).is("a.dropdown-toggle")) {
        closeble = false;
    }

});
$('.dropdown').on({
    "click": function(event) {
        if ($(event.target).closest('.dropdown-toggle').length) {
            closeble = true;
        } else {
            closeble = false;
        }
    },
    "hide.bs.dropdown": function() {
        return closeble;
    }
});

});

-1
répondu julioalberto64 2017-09-14 23:05:56