Evite cerrar el menú desplegable al hacer clic dentro

310

Tengo un menú desplegable de Bootstrap de Twitter. Como todos los usuarios de Twitter Bootstrap saben, el menú desplegable se cierra al hacer clic (incluso haciendo clic dentro de é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 un comportamiento fácil y muy común, y dado que carousel-controls(así como carousel indicators) los controladores de eventos se delegan al documentobjeto, el clickevento 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 dropdown hide/ hiddenevents no es una solución por las siguientes razones:

  • El objeto de evento proporcionado para ambos controladores de eventos no da referencia al elemento cliqueado
  • No tengo control sobre el contenido del menú desplegable, por lo que flagno es posible agregar una clase o atributo

Este violín es el comportamiento normal y este violín se event.stopPropagation()agrega.

Actualizar

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

php-dev
fuente
1. Su jsfiddle no funciona. 2. ¿Qué es exactamente lo que quieres lograr?
paulalexandru
1
@paulalexandru, actualizado, agregó dos violín. Un comportamiento predeterminado y otro con modificación. Intente hacer clic en el botón siguiente y anterior, o en los indicadores. Para el primer ejemplo, el menú se oculta y las diapositivas del carrusel. o el segundo ejemplo: el menú permanece abierto, pero el carrusel no se deslizó desde que event propagationse detuvo.
php-dev
@paulalexandru Entendido, ¿verdad?
php-dev
@ php-dev: lo actualicé nuevamente en aras del desafío, ahora es perfecto ... vea la demostración.
Luca Filosofi

Respuestas:

373

Eliminar el atributo de datos data-toggle="dropdown"e implementar la apertura / cierre del menú desplegable puede ser una solución.

Primero manejando el clic en el enlace para abrir / cerrar el menú desplegable de esta manera:

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

y luego escucha los clics fuera del menú desplegable para cerrarlo así:

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

Aquí está la demostración: http://jsfiddle.net/RomaLefrancois/hh81rhcm/2/

Roma
fuente
2
Esta solución está funcionando bien. La recompensa se le debe otorgar si no hay otra respuesta.
php-dev
1
Su solución es funcional, genérica y también "popular". La recompensa debe otorgarse a su respuesta. También encontré una respuesta, mírela a continuación;)
php-dev
1
@Cichy ... simplemente modifique el primer controlador de esta manera ... $ ('li.dropdown.mega-dropdown a'). On ('click', function (event) {$ ('li.dropdown.mega-dropdown .open '). removeClass (' open '); $ (this) .parent (). toggleClass (' open ');});
dsaket
63
Esta respuesta preferida es un truco. ¡¡¡Guau!!! Aquí hay una respuesta más simple BOOTSTRAP 4 ALPHA para evitar el clic interno en un mega desplegable. // PREVENT INSIDE CLICK DROPDOWN $('.dropdown-menu').on("click.bs.dropdown", function (e) { e.stopPropagation(); e.preventDefault(); });
Frank Thoeny
77
e.stopPropagation()Es la mejor solución.
nacholibre
332

Esto también debería ayudar

$(document).on('click', 'someyourContainer .dropdown-menu', function (e) {
  e.stopPropagation();
});
Arbejdsglæde
fuente
33
Creo que esa es sin duda la solución más simple para este problema. Pulgares arriba: ¡acabo de probar este y funciona!
Torsten Barthel el
13
Esta es, de lejos, la mejor solución.
silencioso
3
Esa es la solución más común, pero tengo un requisito diferente. Lea atentamente mi pregunta :)
php-dev
44
La mejor solución para simplemente mantener el menú abierto con clics.
Matt Pierce
2
La mejor solución de hecho. Personalmente lo usé '.dropdown-menu :not(.dropdown-item)'para que al hacer clic en un dropdown-itemcierre la ventana emergente, pero al hacer clic en un dropdown-headerno.
Benjamin
41

Bootstrap proporciona la siguiente función:

                 El | Este evento se activa inmediatamente cuando el método de instancia de hide
hide.bs.dropdown | ha sido llamado. El elemento de anclaje de alternancia está disponible como
                 El | Propiedad relacionada de destino del evento.

Por lo tanto, la implementación de esta función debería poder desactivar el cierre desplegable.

$('#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
fuente
2
@Vartan, también la targetpropiedad del evento es el li.dropdown, el relatedTargetes el a.dropdown-toggle. Por lo tanto, no puede hacer referencia al elemento en el que se hizo clic en el hidecontrolador de eventos.
php-dev
2
hasClass toma un nombre de clase, no un selector CSS. target.hasClass(".keepopen")debería ser target.hasClass("keepopen"). De lo contrario, el código no funcionará.
Hugh Guiney
3
He escaneado Internet y esta es la solución más inteligente con diferencia, por esta razón ... muchos otros métodos requieren un enfoque que use detener el evento predeterminado o detener la propagación. estos enfoques son muy malos ya que romperán cualquier otro evento desencadenado dentro del menú desplegable (es decir, mis elementos de formulario móvil jquery) usando este enfoque le permite identificar específicamente cuándo se está cerrando el menú y le permite actuar solo en ese evento. esta respuesta necesita tantas estrellas ...
webfish
3
@webfish ¿Cuánto te llevó escanear Internet? (rofl)
php-dev
2
Quizás esto solía funcionar ... pero con bootstrap 4, e.target es siempre el menú desplegable. No es el objetivo seleccionado. Incluso si hace clic fuera de los menús desplegables, e.target sigue siendo el menú desplegable. Por lo tanto, no puede realizar este tipo de verificación. ¿Alguien ve una forma de evitar esto?
FredArters
36

La mejor respuesta absoluta es poner 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>
Gregory Bowers
fuente
2
funcionalmente funcionó espléndidamente para mí, pero rompió el estilo
2778
2
esta fue la solución más rápida para mí
Jonathan Morales Vélez
15
Esta no es la mejor respuesta :) un <li>elemento no debe estar dentro de un <form> elemento.
GETah
2
Esta no es una solución semánticamente correcta: el único hijo válido de un UL es un LI; en todo caso, las etiquetas de formulario deben estar dentro de las etiquetas li, pero eso puede no ser la acción deseada, de cualquier manera un ul> form> li no es marcado correcto
gavgrif 01 de
2
Gracias por esta solución rápida
Herman Demsong
27

También encontré una solución.

Suponiendo que los Twitter Bootstrap Componentscontroladores de eventos relacionados se delegan en el documentobjeto, repito los controladores adjuntos y verifico si el elemento en el que se hace clic (o uno de sus padres) está afectado por un evento delegado.

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

Espero que ayude a cualquiera que busque una solución similar.

Gracias por toda tu ayuda.

php-dev
fuente
1
¡¡¡Guau!!! funcionó a la perfección! Estuve en problemas durante una semana, estoy usando mCustomeScrollbar y después de hacer clic en la barra de desplazamiento en el menú desplegable lo estaba cerrando, su script funcionó y ahora funciona bien. Un millón de gracias.
eirenaios
¡Funciona genial! ¿Cómo se extiende esto, para que un usuario pueda seguir presionando "ESC" (o incluso hacer clic afuera) en el teclado para cerrar el DD?
Tío Iroh el
2
@MaggewDotCom La pulsación de la tecla ESC aún debería funcionar. Lo mismo para hacer clic afuera ...
php-dev
El único inconveniente de esta solución es que no permite desplegables anidados (digamos que tiene un dropright dentro de un desplegable). ¿Hay alguna solución para este caso?
sdvnksv
26

Esto podría ayudar:

$("dropdownmenuname").click(function(e){
   e.stopPropagation();
})
Bawantha
fuente
Esta es definitivamente la respuesta más simple / mejor si desea que un usuario interactúe con un elemento de la interfaz de usuario presente en el menú desplegable (por ejemplo, botones de radio) y no desea que el menú se cierre cuando alternan las opciones.
Rob
22
$('body').on("click", ".dropdown-menu", function (e) {
    $(this).parent().is(".open") && e.stopPropagation();
});

Esto puede funcionar para cualquier condición.

Terry Lin
fuente
esta debería ser la respuesta correcta, ya que utiliza menos líneas de código en lugar de la respuesta seleccionada
Muhammad Omer Aslam
@MuhammadOmerAslam Nah! Como no cumple con mi requisito
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>

Manifestación :

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

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

Kerry Johnson
fuente
9

Intenté esta cosa simple y funcionó a las mil maravillas.

Cambié el elemento del menú desplegable de <div>a <form>y funcionó bien.

<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
fuente
6

Recientemente tuve un problema similar y probé diferentes formas de resolverlo eliminando el atributo de datos data-toggle="dropdown"y escuchando clickconevent.stopPropagation() llamadas.

La segunda forma parece 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);

Entonces, esta línea:

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

sugiere que puede colocar un formelemento dentro del contenedor con clase .dropdownpara evitar cerrar el menú desplegable.

Ilya
fuente
6

Bootstrap ha resuelto este problema ellos mismos en su soporte para <form>etiquetas en 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 evitar la propagación en el elemento del documento y hacerlo solo para eventos de tipo 'click.bs.dropdown.data-api'que coinciden con el selector '.dropdown .your-custom-class-for-keep-open-on-click-elements'.

O en código

$(document).on('click.bs.dropdown.data-api', '.dropdown .keep-open-on-click', (event) => {
    event.stopPropagation();
});
Daniel Schlaug
fuente
1
Gracias, gracias, gracias por el enlace a la fuente. Para otros que se preguntan por qué el formenfoque de los ejemplos no funciona para ustedes: estaba usando class dropleft, pero también es necesario dropdownpara que el selector de formularios coincida.
Mark K Cowan
6

Modifiqué la respuesta de @ Vartan para que funcione con Bootstrap 4.3. Su solución ya no funciona con la última versión, ya que la targetpropiedad siempre devuelve la raíz del menú desplegablediv sin importar dónde se colocó el clic.

Aquí está el código:

$('.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
fuente
en línea:$('.dropdown-keep-open').on('hide.bs.dropdown', ev => !(ev.clickEvent && $(ev.target).has(ev.clickEvent.target).length))
Matveev Dmitriy
@MatveevDmitriy Lo siento, pero nadie, simplemente nadie puede leer este trazador de líneas. Escribir código de esta manera es, en mi opinión, una mala práctica.
ViRuSTriNiTy
La última línea se puede simplificar usando return !target.closest('.dropdown-keep-open').length). Dicho esto, esta es una gran solución! Encontré esto necesario para resolver este problema.
patrick3853
6
$('body').on("click", ".dropdown-menu", function (e) {
    $(this).parent().is(".show") && e.stopPropagation();
});
waza123
fuente
Primero, gracias por tu respuesta. La pregunta ya está respondida. Además, tengo un requisito diferente como se describe en la pregunta que el requisito común.
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');
});

Lo he actualizado una vez más para que sea lo más inteligente y funcional posible. ahora se cierra cuando pasa el cursor fuera del navegador y permanece abierto mientras está dentro. Simplemente perfecto.

Luca Filosofi
fuente
Su solución es inteligente debido a su brevedad, sin embargo, después de agregar la clase show, el menú desplegable no se cierra al hacer clic afuera, y tenemos que hacer clic en el botón desplegable antes de ... +1 de todos modos
php-dev
Lo he actualizado, mira la demo. es la mejor causa, no verifique el evento de clic del cuerpo cada vez. afecta solo el elemento dentro de cada elemento de navegación no fuera de él.
Luca Filosofi
Mi solución tampoco depende del bodyevento de clic ^^
php-dev
sí, se retransmite en parte en el evento de clic del cuerpo, intenta verificar qué elemento se ha hecho clic en la delegación del cuerpo. $('body').on('click', function (e) {
Luca Filosofi
Nah! Esa no es mi respuesta. Mi respuesta es la última publicada.
php-dev
4

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();                
});
Frank Thoeny
fuente
1
e.preventDefault();bloquea enlaces, puede omitirlo
largo
@czachor tienes razón! e.preventDefault (); Evite que un enlace siga la URL.
Frank Thoeny
3

Puede detener la propagación del clic en el menú desplegable y luego volver a implementar manualmente los controles del carrusel utilizando los métodos de JavaScript del carrusel .

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

Aquí está el jsfiddle .

Neil
fuente
Su ejemplo funciona bien, pero el problema es que el menú desplegable puede contener cualquier contenido y no solo imágenes carrusel ...
php-dev
3

Con Angular2 Bootstrap, puede usar nonInput para la mayoría de los escenarios:

<div dropdown autoClose="nonInput">

nonInput: (valor predeterminado) cierra automáticamente el menú desplegable cuando se hace clic en cualquiera de sus elementos, siempre que el elemento seleccionado no sea una entrada o un área de texto.

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

Nir Soudry
fuente
2

Sé que esta pregunta fue específicamente para jQuery, pero para cualquiera 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-closea su elemento que está activando el menú para cerrar, y debería evitarlo. Para mí, fue un selectelemento 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>
jtate
fuente
66
<div class="dropdown-menu" ng-click="$event.stopPropagation()">funciona para mí en 1.2.x
dr3w
2

[Bootstrap 4 Alpha 6] [Rails] para los carriles desarrollador, e.stopPropagation()dará lugar a un comportamiento indeseable para link_tocon data-methodno ser igual a get, ya que lo hará por retorno por defecto toda su petición como get.

Para solucionar este problema, sugiero esta solución, que es universal

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

Jacky Tong
fuente
2

En lugar de escribir un código javascript o jquery (reinventando la rueda). El escenario anterior se puede administrar mediante la opción de cierre automático de bootstrap. Puede proporcionar cualquiera de los valores para cerrar automáticamente :

  1. siempre: (predeterminado) cierra automáticamente el menú desplegable cuando se hace clic en cualquiera de sus elementos.

  2. outsideClick: cierra el menú desplegable automáticamente solo cuando el usuario hace clic en cualquier elemento fuera del menú desplegable.

  3. disabled: desactiva el cierre automático

Eche un vistazo al siguiente plunkr:

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

Conjunto

uib-dropdown auto-close="disabled" 

Espero que esto ayude :)

ashwaniKumar
fuente
55
Cabe señalar explícitamente que esto solo es bueno para las personas que usan ui-bootstrap, lo que probablemente no sea el caso para muchas personas que ven esta pregunta.
kevlarr
Lo describiste bien, pero creo que deberías escribir la solución como uib-dropdown auto-close="outsideClick". El menú cerrado al hacer clic dentro es un poco incómodo, pero el menú que no se cierra al hacer clic afuera es bastante molesto.
vusan
2

Sé que ya hay una respuesta anterior que sugiere utilizar un formulario, pero el marcado proporcionado no es correcto / ideal. Esta es la solución más fácil, no se necesita JavaScript en absoluto y no rompe su menú desplegable. Funciona con Bootstrap 4.

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

Radu Ciobanu
fuente
@RosdiKasim Lo tengo funcionando bien en un sitio web con Bootstrap 4.0.0. No he probado con 4.1
Radu Ciobanu
En realidad debería ser como: <form class = "dropdown dropdown-item">
Nasser Sadraee
2

Esto me ayudo

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

El elemento del menú desplegable debe ser así (tome nota de las clases dropdown-menuy keepopen.

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

El código anterior evita hacer una oferta en general <body>, en lugar del elemento específico con la clase dropdown-menu.

Espero que esto ayude a alguien.

Gracias.

Anjana Silva
fuente
Gracias Actualizado según Bootstrap 4 $ ('. Dropdown-menu [data-handleropdownclose = "true"]'). On ('click', function (e) {if ($ (this) .parent (). Is (" .show ")) {var target = $ (e.target); return (target.hasClass (" CloseDropDown ") || target.parents (". CloseDropDown "). length);}});
Thulasiram
1

La solución de trabajo más simple para mí es:

  • la adición de keep-openla clase a elementos que no debe provocar el cierre desplegable
  • y este código hace el resto:
$('.dropdown').on('click', function(e) {
    var target = $(e.target);
    var dropdown = target.closest('.dropdown');
    return !dropdown.hasClass('open') || !target.hasClass('keep-open');
});
Gee-Bee
fuente
¿pueden ayudarme a solucionar este stackoverflow.com/questions/51552712/… @ Gee-Bee
Zhu
1

No he encontrado que ninguna de las soluciones funcionó, ya que me gustaría usar el navegador de arranque 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;
       });
Miguel
fuente
1

En .dropdowncontenido, coloque la .keep-openclase en cualquier etiqueta así:

$('.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 evitaban los eventos relacionados con los objetos del contenedor, ahora el contenedor hereda la clase keep-open y check antes de cerrarse.

Feria Dixán Santiesteban
fuente
1

Lo hice con esto:

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

Para cerrar el menú desplegable solo si se activó un evento de clic fuera del menú desplegable de arranque, esto es lo que funcionó para mí:

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

Archivo 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
fuente
0

Puede tener algunos problemas si usa el método return false o stopPropagation () porque sus eventos serán interrumpidos. Pruebe este código, funciona 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 quieres cerrar el dropdrown:

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

En Bootstrap 4 también puedes hacer esto:

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

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

donde #dd-linkestá el elemento de anclaje o botón que tiene la data-toggle="drowndown"propiedad

Daniel
fuente