Evite fechar o menu suspenso ao clicar dentro

310

Eu tenho um menu suspenso Twitter Bootstrap. Como todos os usuários do Twitter Bootstrap sabem, o menu suspenso se fecha ao clicar (mesmo clicando dentro dele).

Para evitar isso, posso anexar facilmente um manipulador de eventos de clique no menu suspenso e simplesmente adicionar o 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>

Isso parece fácil e um comportamento muito comum, no entanto, e como carousel-controls(assim como carousel indicators) os manipuladores de eventos são delegados ao documentobjeto, o clickevento nesses elementos ( controles anteriores / próximos , ...) 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();
});

Contar com o menu suspenso hide/ hiddeneventos do Bootstrap do Twitter não é uma solução pelos seguintes motivos:

  • O objeto de evento fornecido para os dois manipuladores de eventos não fornece referência ao elemento clicado
  • Como não tenho controle sobre o conteúdo do menu suspenso, flagnão é possível adicionar uma classe ou atributo

Este violino é o comportamento normal e esse violino é event.stopPropagation()adicionado.

Atualizar

Agradeço a Roman por sua resposta . Eu também encontrei uma resposta que você pode encontrar abaixo .

php-dev
fonte
1. Seu jsfiddle não está funcionando. 2. O que exatamente você deseja alcançar?
paulalexandru
1
@paulalexandru, Atualizado, adicionou dois violinos. Um comportamento padrão e outro com modificação. Tente clicar no botão próximo e anterior ou nos indicadores. Para o primeiro exemplo, o menu oculta e o carrossel desliza. ou o segundo exemplo: o menu permanece aberto, mas o carrossel não deslizou desde que o event propagationitem foi parado.
Php-dev
@paulalexandru Entendi, certo?
Php-dev
@ php-dev: atualizei-o novamente por uma questão de desafio, agora é perfeito ... veja a demonstração.
Luca Filosofi 12/08

Respostas:

373

Remover o atributo de dados data-toggle="dropdown"e implementar a abertura / fechamento da lista suspensa pode ser uma solução.

Primeiro, manipule o clique no link para abrir / fechar o menu suspenso assim:

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

e depois ouvir os cliques fora do menu suspenso para fechá-lo assim:

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

Aqui está a demonstração: http://jsfiddle.net/RomaLefrancois/hh81rhcm/2/

Roma
fonte
2
Esta solução está funcionando bem. A recompensa deve ser concedida a você se não houver outra resposta.
Php-dev
1
Sua solução está funcionando, genérica e também "popular". A recompensa deve ser concedida à sua resposta. Eu também achei uma resposta, olhada abaixo;)
php-dev
1
@ Cichy ... apenas modifique o primeiro manipulador como este ... $ ('li.dropdown.mega-dropdown a'). On ('click', function (event) {$ ('li.dropdown.mega-dropdown Abra o arquivo .class () e abra o arquivo .class ();
dsaket
63
Essa resposta preferida é um hack. Uau!!! Aqui está uma resposta mais simples do BOOTSTRAP 4 ALPHA para evitar cliques internos em um mega menu suspenso. // PREVENT INSIDE CLICK DROPDOWN $('.dropdown-menu').on("click.bs.dropdown", function (e) { e.stopPropagation(); e.preventDefault(); });
precisa
7
e.stopPropagation()é a melhor solução.
Nacholibre 29/03/19
332

Isso deve ajudar também

$(document).on('click', 'someyourContainer .dropdown-menu', function (e) {
  e.stopPropagation();
});
Arbejdsglæde
fonte
33
Eu acho que é com certeza a solução mais simples para esse problema. Polegares para cima - apenas testei este e ele funciona!
Torsten Barthel
13
Esta é de longe a melhor solução.
silencioso
3
Essa é a solução mais comum, mas eu tenho um requisito diferente. Por favor, leia atentamente a minha pergunta :)
php-dev
4
A melhor solução para simplesmente manter o menu aberto em cliques.
Matt Pierce
2
Melhor solução, de fato. Eu pessoalmente usei '.dropdown-menu :not(.dropdown-item)'para que clicar em um dropdown-itemfecha o pop-up, mas clicar em um dropdown-headernão.
Benjamin
41

O Bootstrap fornece a seguinte função:

                 | Este evento é acionado imediatamente quando o método de instância hide
hide.bs.dropdown | tem sido chamado. O elemento de âncora de alternância está disponível como o
                 | propriedade relatedTarget do evento.

Portanto, a implementação dessa função deve poder desativar o fechamento da lista suspensa.

$('#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
fonte
2
@Vartan, também a targetpropriedade do evento é a li.dropdown, relatedTargeté a a.dropdown-toggle. Portanto, você não pode se referir ao elemento clicado no hidemanipulador de eventos.
Php-dev
2
O hasClass usa um nome de classe, não um seletor de CSS. target.hasClass(".keepopen")deveria ser target.hasClass("keepopen"). Caso contrário, o código não funcionará.
Hugh Guiney
3
Examinei a Internet e essa é a solução mais inteligente, de longe, por esse motivo ... outros métodos exigem uma abordagem que use a interrupção do evento padrão ou a propagação. essas abordagens são muito ruins, pois interromperão qualquer outro evento acionado dentro da lista suspensa (ou seja, meus elementos de formulário móvel do jquery). Essa abordagem permite identificar especificamente quando o menu em si está sendo fechado e permitir que você execute ações somente nesse evento. esta resposta precisa de tantas estrelas ....
webfish
3
@webfish Quanto você levou para escanear a internet? (rofl)
php-dev
2
Talvez isso funcionasse .. mas com o bootstrap 4, o e.target é sempre o próprio menu suspenso. Não é o destino clicado. Mesmo se você clicar fora das listas suspensas, e.target ainda será a lista suspensa. Portanto, você não pode executar esse tipo de verificação. Alguém vê uma maneira de contornar isso?
21918 FredArters
36

A melhor resposta absoluta é colocar uma tag de formulário após o menu suspenso da classe

então seu código é

<ul class="dropdown-menu">
  <form>
    <li>
      <div class="menu-item">bla bla bla</div>
    </li>
  </form>
</ul>
Gregory Bowers
fonte
2
funcionalmente trabalhou esplendidamente para mim, mas quebrou o styling
2778
2
esta foi a solução mais rápida para mim #
Jonathan Morales Vélez
15
Esta não é a melhor resposta :) um <li>elemento não deve estar dentro de um <form> elemento.
Getah
2
Esta não é uma solução semanticamente correta - o único filho válido de um UL é um LI - se alguma coisa as tags de formulário estiverem dentro das tags li - mas isso não pode impedir a ação desejada - de qualquer maneira uma ul> form> li não é marcação correta
gavgrif
2
Thnaks para esta solução rápida
Herman Demsong
27

Eu também encontrei uma solução.

Supondo que os Twitter Bootstrap Componentsmanipuladores de eventos relacionados sejam delegados ao documentobjeto, faço um loop nos manipuladores anexados e verifico se o elemento clicado atual (ou um de seus pais) está relacionado a um 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 ajude quem procura uma solução semelhante.

Obrigado a todos por sua ajuda.

php-dev
fonte
1
Uau!!! funcionou perfeitamente! Estava com problemas por uma semana, estou usando o mCustomeScrollbar e, depois de clicar na barra de rolagem, ele estava sendo fechado, seu script funcionou e agora está funcionando bem! Graças um milhão.
eirenaios
funciona bem! como se estende isso, para que um usuário ainda possa pressionar "ESC" (ou até clicar fora) no teclado para fechar o DD?
Tio Iroh
2
@ MaggewDotCom A tecla ESC ainda deve funcionar. O mesmo para clicar fora ...
php-dev
A única desvantagem desta solução é que ela não permite dropdowns aninhados (digamos que você tenha um direito dentro de um dropdown). Existe uma solução alternativa para este caso?
Sdvnksv 26/10/19
26

Isso pode ajudar:

$("dropdownmenuname").click(function(e){
   e.stopPropagation();
})
Bawantha
fonte
Essa é definitivamente a resposta mais simples / melhor se você deseja que um usuário interaja com um elemento da interface do usuário presente no menu suspenso (por exemplo, botões de opção) e não deseja que o menu seja fechado quando alternar as opções.
1526 Rob
22
$('body').on("click", ".dropdown-menu", function (e) {
    $(this).parent().is(".open") && e.stopPropagation();
});

Isso pode funcionar para qualquer condição.

Terry Lin
fonte
esta deve ser a resposta correcta, uma vez que usa menos linhas de código em vez da resposta escolhida
Muhammad Omer Aslam
@MuhammadOmerAslam Nah! Como ele não cumprir a minha obrigação
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>

Demo :

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

Sua demonstração com esta solução: http://jsfiddle.net/kerryjohnson/80oLdtbf/101/

Kerry Johnson
fonte
9

Eu tentei essa coisa simples e funcionou como um encanto.

Alterei o elemento do menu suspenso de <div>para <form>e funcionou bem.

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

Eu tenho um problema semelhante recentemente e tentou diferentes maneiras de resolvê-lo com a remoção do atributo de dados data-toggle="dropdown"e ouvindo clickcom event.stopPropagation()ligando.

A segunda maneira parece mais preferível. Os desenvolvedores de Bootstrap também usam dessa maneira. No arquivo de origem, encontrei a inicialização dos elementos suspensos:

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

Então, esta linha:

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

sugere que você possa colocar um formelemento dentro do contêiner com a classe .dropdownpara evitar fechar o menu suspenso.

Ilya
fonte
6

O Bootstrap resolveu esse problema eles mesmos no suporte a <form>tags em listas suspensas. A solução deles é bastante compreensível e você pode lê-lo aqui: https://github.com/twbs/bootstrap/blob/v4-dev/js/src/dropdown.js

Tudo se resume a impedir a propagação no elemento do documento e fazê-lo apenas para eventos do tipo 'click.bs.dropdown.data-api'que correspondem ao seletor '.dropdown .your-custom-class-for-keep-open-on-click-elements'.

Ou no código

$(document).on('click.bs.dropdown.data-api', '.dropdown .keep-open-on-click', (event) => {
    event.stopPropagation();
});
Daniel Schlaug
fonte
1
Obrigado obrigado obrigado pelo link para a fonte. Para outros que se perguntam por que a formabordagem dos exemplos não está funcionando para você - eu estava usando a classe dropleft, mas também precisa dropdownpara que o seletor de formulários corresponda.
Mark K Cowan
6

Modifiquei a resposta do @ Vartan para fazê-lo funcionar com o Bootstrap 4.3. Sua solução não funciona mais com a versão mais recente, pois a targetpropriedade sempre retorna a raiz do menu suspenso, divnão importa onde o clique foi colocado.

Aqui está o 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
fonte
on-line:$('.dropdown-keep-open').on('hide.bs.dropdown', ev => !(ev.clickEvent && $(ev.target).has(ev.clickEvent.target).length))
Matveev Dmitriy
@MatveevDmitriy Sinto muito, mas ninguém, simplesmente ninguém pode ler este forro. Escrever código dessa maneira é uma prática ruim.
ViRuSTriNiTy 9/03
A última linha pode ser simplificada usando return !target.closest('.dropdown-keep-open').length). Dito isto, esta é uma ótima solução! Achei isso necessário para resolver esse problema.
patrick3853
6
$('body').on("click", ".dropdown-menu", function (e) {
    $(this).parent().is(".show") && e.stopPropagation();
});
waza123
fonte
Primeiro, obrigado pela sua resposta. A pergunta já está respondida. Além disso, tenho um requisito diferente, conforme descrito na pergunta, do que o requisito comum.
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');
});

Atualizei-o novamente para ser o mais inteligente e funcional possível. agora fecha quando você passa o mouse fora da nav, permanecendo aberto enquanto estiver dentro dela. simplesmente perfeita.

Luca Filosofi
fonte
Sua solução é inteligente devido à sua falta, no entanto, após a adição da classe show, o menu suspenso não fecha ao clicar fora, e precisamos clicar no menu suspenso antes de ... +1 de qualquer maneira
php-dev
Eu atualizei, veja a demonstração. é a melhor causa, não verifique o evento de clique no corpo toda vez. afetam apenas o elemento dentro de cada elemento nav não fora dele.
Luca Filosofi 12/08
Minha solução também não dependem de bodyevento clique ^^
php-dev
sim, ele retransmite parcialmente o evento de clique no corpo, tenta verificar em qual elemento foi clicado através da delegação do corpo. $('body').on('click', function (e) {
Luca Filosofi
Nah! Essa não é a minha resposta. Minha resposta é a última postada.
Php-dev
4

Como por exemplo, o Bootstrap 4 Alpha possui este Menu Event. Por que não usar?

// PREVENT INSIDE MEGA DROPDOWN
$('.dropdown-menu').on("click.bs.dropdown", function (e) {
    e.stopPropagation();
    e.preventDefault();                
});
Frank Thoeny
fonte
1
e.preventDefault();bloqueia links, você pode ignorá-lo
long
@czachor você está certo! e.preventDefault (); Impedir que um link siga o URL.
24518 Frank Thoeny
3

Você pode interromper a propagação da lista suspensa e reimplementar manualmente os controles do carrossel usando métodos javascript do carrossel .

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

Aqui está o jsfiddle .

Neil
fonte
Seu exemplo funciona bem, mas o problema é que o menu suspenso pode conter qualquer conteúdo e não só imagens carrossel ...
php-dev
3

Com o Angular2 Bootstrap, você pode usar nonInput na maioria dos cenários:

<div dropdown autoClose="nonInput">

nonInput - (padrão) fecha automaticamente a lista suspensa quando qualquer um de seus elementos é clicado - desde que o elemento clicado não seja uma entrada ou uma área de texto.

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

Nir Soudry
fonte
2

Eu sei que esta pergunta foi especificamente para jQuery, mas para quem usa AngularJS com esse problema, você pode criar uma diretiva que lida com isso:

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

Em seguida, basta adicionar o atributo dropdown-prevent-closeao seu elemento que está acionando o menu para fechar, e isso deve impedi-lo. Para mim, foi um selectelemento que fechou automaticamente o menu:

<div class="dropdown-menu">
  <select dropdown-prevent-close name="myInput" id="myInput" ng-model="myModel">
    <option value="">Select Me</option>
  </select>
</div>
jtate
fonte
6
<div class="dropdown-menu" ng-click="$event.stopPropagation()">funciona para mim no 1.2.x
dr3w 06/07
2

[Bootstrap 4 Alpha 6] [Rails] para o Rails desenvolvedor, e.stopPropagation()vai levar a um comportamento indesejável para link_tocom data-methodnão é igual a getuma vez que, por padrão, devolver todo o seu pedido oget .

Para remediar esse problema, sugiro esta solução, que é universal

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

Jacky Tong
fonte
2

Em vez de escrever algum código javascript ou jquery (reinventar a roda). O cenário acima pode ser gerenciado pela opção de fechamento automático de autoinicialização. Você pode fornecer um dos valores para fechar automaticamente :

  1. sempre - (Padrão) fecha automaticamente o menu suspenso quando qualquer um dos seus elementos é clicado.

  2. outsideClick - fecha a lista suspensa automaticamente somente quando o usuário clica em qualquer elemento fora da lista suspensa.

  3. desabilitado - desativa o fechamento automático

Dê uma olhada no seguinte plunkr:

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

Conjunto

uib-dropdown auto-close="disabled" 

Espero que isto ajude :)

ashwaniKumar
fonte
5
Deve-se notar explicitamente que isso é bom apenas para as pessoas que usam ui-bootstrap, o que provavelmente não é o caso de muitas pessoas que visualizam essa pergunta.
precisa saber é o seguinte
Você descreveu bem, mas acho que deveria escrever a solução como uib-dropdown auto-close="outsideClick". O menu fechar ao clicar dentro é apenas um pouco desconfortável, mas o menu não fecha ao clicar fora é bastante perturbador.
vusan
2

Sei que já existe uma resposta anterior sugerindo o uso de um formulário, mas a marcação fornecida não está correta / ideal. Aqui está a solução mais fácil, não é necessário javascript e isso não interrompe o seu menu suspenso. Funciona com o Bootstrap 4.

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

Radu Ciobanu
fonte
@RosdiKasim Estou funcionando bem em um site com o Bootstrap 4.0.0. Não testei com 4,1
Radu Ciobanu
Na verdade, deve ser como: <form class = "dropdown dropdown-item">
Nasser Sadraee
2

Isso me ajudou,

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

Seu elemento do menu suspenso precisa ser assim (observe as classes dropdown-menue keepopen.

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

O código acima evita a espera geral <body>, em vez do elemento específico da classe dropdown-menu.

Espero que isso ajude alguém.

Obrigado.

Anjana Silva
fonte
Agradecimentos atualizados conforme o Bootstrap 4 $ ('. Menu suspenso [data-handledropdownclose = "true"]'). On ('clique', função (e) {if ($ (this) .parent (). Is (" .show ")) {var target = $ (e.target); return (target.hasClass (" CloseDropDown ") || target.parents (". CloseDropDown "). length);}});
Thulasiram 29/04
1

A solução de trabalho mais simples para mim é:

  • adicionando keep-openclasse a elementos que não devem causar fechamento suspenso
  • e este pedaço de código faz o 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
fonte
você pode por favor me ajudar a consertar esse stackoverflow.com/questions/51552712/… @ Gee-Bee
Zhu
1

Descobri que nenhuma das soluções funcionou como gostaria de usar a navegação padrão de inicialização. Aqui está minha solução para esse problema:

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

No .dropdownconteúdo, coloque a .keep-openclasse em qualquer etiqueta da seguinte 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
    }
});

Os casos anteriores evitavam os eventos relacionados aos objetos de contêiner, agora o contêiner herda a classe keep-open e check antes de ser fechado.

Dixán Santiesteban Feria
fonte
1

Eu fiz isso com isso:

$(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
fonte
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
fonte
0

Para fechar a lista suspensa apenas se um evento de clique foi acionado fora da lista suspensa de inicialização, é isso que funcionou para mim:

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

Arquivo 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
fonte
0

Você pode ter alguns problemas se usar o método return false ou stopPropagation () porque seus eventos serão interrompidos. Experimente este código, funciona bem:

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

Em 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>

Se você deseja fechar o dropdrown:

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

No Bootstrap 4, você também pode fazer isso:

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

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

onde #dd-linké o elemento âncora ou botão que possui a data-toggle="drowndown"propriedade

Daniel
fonte