javascript - Evitar cerrar el menú desplegable al hacer clic dentro



12 Answers

Esto debería ayudar también

$(document).on('click', 'someyourContainer .dropdown-menu', function (e) {
  e.stopPropagation();
});
javascript jquery html twitter-bootstrap-3 drop-down-menu

Tengo un menú desplegable de Twitter Bootstrap. Como todos los usuarios de Twitter Bootstrap saben, el menú desplegable se cierra al hacer clic (incluso al hacer clic en él).

Para evitar esto, puedo adjuntar fácilmente un controlador de eventos de clic en el menú desplegable y simplemente agregar el famoso 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>

Sin embargo, esto parece fácil y es un comportamiento muy común, y como carousel-controls eventos carousel-controls (así como los carousel indicators ) se delegan al objeto del document , el evento de click en estos elementos (controles anterior / siguiente , ...) será "Ignorado".

$('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();
});

Confiar en Twitter Bootstrap desplegable hide / eventos hidden no es una solución por las siguientes razones:

  • El evento proporcionado para ambos controladores de eventos no le da referencia al elemento en el que se hizo clic
  • El contenido del menú desplegable se genera dinámicamente, por lo que no es posible agregar una clase de marca

Este violín es el comportamiento normal y este violín es con el event.stopPropagation() agregado.

Actualizar

Gracias a Roman por su respuesta . También encontré una respuesta que puedes encontrar a continuación .




La mejor respuesta absoluta es colocar una etiqueta de formulario después del menú desplegable de la clase

entonces tu código es

<ul class="dropdown-menu">
  <form>
    <li>
      <div class="menu-item">bla bla bla</div>
    </li>
  </form>
</ul>



$('body').on("click", ".dropdown-menu", function (e) {
    $(this).parent().is(".open") && e.stopPropagation();
});

Esto puede funcionar para cualquier condición.




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>

Demostración :

Genérico: https://jsfiddle.net/kerryjohnson/omefq68b/1/

Su demostración con esta solución: http://jsfiddle.net/kerryjohnson/80oLdtbf/101/




Tengo un problema similar recientemente e intenté diferentes maneras de resolverlo eliminando el atributo de data-toggle="dropdown" y escuchando haciendo click con el event.stopPropagation() llamando.

La segunda forma se ve más preferible. También los desarrolladores de Bootstrap usan de esta manera. En el archivo fuente encontré la inicialización de los elementos desplegables:

// 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);

Por lo tanto, esta línea:

.on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })

sugiere que puede colocar un elemento de form dentro del contenedor con la clase .dropdown para evitar cerrar el menú desplegable.




Como, por ejemplo, Bootstrap 4 Alpha tiene este evento de menú. ¿Por qué no usar?

// PREVENT INSIDE MEGA DROPDOWN
$('.dropdown-menu').on("click.bs.dropdown", function (e) {
    e.stopPropagation();
    e.preventDefault();                
});



Sé que esta pregunta fue específicamente para jQuery, pero para cualquier persona que use AngularJS que tenga este problema, puede crear una directiva que maneje esto:

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
          });
        }
    };
});

Luego simplemente agregue el atributo dropdown-prevent-close a su elemento que está activando el cierre del menú, y debería evitarlo. Para mí, fue un elemento de select que cerró automáticamente el menú:

<div class="dropdown-menu">
  <select dropdown-prevent-close name="myInput" id="myInput" ng-model="myModel">
    <option value="">Select Me</option>
  </select>
</div>



$('body').on("click", ".dropdown-menu", function (e) {
    $(this).parent().is(".show") && e.stopPropagation();
});

esto funciona en 2018




No he encontrado ninguna de las soluciones que funcionen como me gustaría usar el bootstrap nav predeterminado. Aquí está mi solución a este problema:

       $(document).on('hide.bs.dropdown', function (e) {
        if ($(e.currentTarget.activeElement).hasClass('dropdown-toggle')) {
          $(e.relatedTarget).parent().removeClass('open');
          return true;
        }
        return false;
       });



En el contenido de .dropdown , coloque la clase .keep-open en cualquier etiqueta, de esta forma:

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

Los casos anteriores evitaron los eventos relacionados con los objetos del contenedor, ahora el contenedor hereda la clase keep-open y se comprueba antes de cerrarse.




$(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')
    });
});



Bootstrap ha resuelto este problema ellos mismos en su compatibilidad con las etiquetas <form> en los menús desplegables. Su solución es bastante comprensible y puede leerla aquí: https://github.com/twbs/bootstrap/blob/v4-dev/js/src/dropdown.js

Se reduce a prevenir la propagación en el elemento del documento y solo lo hace para eventos del tipo 'click.bs.dropdown.data-api' que coinciden con el selector '.dropdown .your-custom-class-for-keep-open-on-click-elements' .

O en codigo

$(document).on('click.bs.dropdown.data-api', '.dropdown .keep-open-on-click', (event) => {
    event.stopPropagation();
});



Related