¿Cómo descartar una ventana emergente de Twitter Bootstrap haciendo clic afuera?

Resuelto Ante Vrli asked hace 12 años • 41 respuestas

¿Podemos hacer que los popovers sean descartables de la misma manera que los modales, es decir? ¿Hacerlos cerrar cuando el usuario hace clic en algún lugar fuera de ellos?

Desafortunadamente, no puedo usar modal real en lugar de popover, porque modal significa posición: fija y eso ya no sería popover. :(

Ante Vrli avatar Jul 29 '12 00:07 Ante Vrli
Aceptado

Actualización: una solución un poco más sólida: http://jsfiddle.net/mattdlockyer/C5GBU/72/

Para botones que contienen solo texto:

$('body').on('click', function (e) {
    //did not click a popover toggle or popover
    if ($(e.target).data('toggle') !== 'popover'
        && $(e.target).parents('.popover.in').length === 0) { 
        $('[data-toggle="popover"]').popover('hide');
    }
});

Para botones que contienen íconos, use (este código tiene un error en Bootstrap 3.3.6, consulte la solución a continuación en esta respuesta)

$('body').on('click', function (e) {
        //did not click a popover toggle, or icon in popover toggle, or popover
        if ($(e.target).data('toggle') !== 'popover'
            && $(e.target).parents('[data-toggle="popover"]').length === 0
            && $(e.target).parents('.popover.in').length === 0) { 
            $('[data-toggle="popover"]').popover('hide');
        }
    });

Para popovers generados por JS Úselo '[data-original-title]'en lugar de'[data-toggle="popover"]'

Advertencia: la solución anterior permite abrir varias ventanas emergentes a la vez.

Un popover a la vez, por favor:

Actualización: Bootstrap 3.0.x, consulte el código o toque el violín http://jsfiddle.net/mattdlockyer/C5GBU/2/

$('body').on('click', function (e) {
    $('[data-toggle="popover"]').each(function () {
        //the 'is' for buttons that trigger popups
        //the 'has' for icons within a button that triggers a popup
        if (!$(this).is(e.target) && $(this).has(e.target).length === 0 && $('.popover').has(e.target).length === 0) {
            $(this).popover('hide');
        }
    });
});

Esto maneja el cierre de ventanas emergentes que ya están abiertas y en las que no se ha hecho clic o en sus enlaces no se ha hecho clic.


Actualización: Bootstrap 3.3.6, ver violín

Soluciona el problema por el cual, después de cerrar, se necesitan 2 clics para volver a abrir

$(document).on('click', function (e) {
    $('[data-toggle="popover"],[data-original-title]').each(function () {
        //the 'is' for buttons that trigger popups
        //the 'has' for icons within a button that triggers a popup
        if (!$(this).is(e.target) && $(this).has(e.target).length === 0 && $('.popover').has(e.target).length === 0) {                
            (($(this).popover('hide').data('bs.popover')||{}).inState||{}).click = false  // fix for BS 3.3.6
        }

    });
});

Actualización: Utilizando el condicional de la mejora anterior, se logró esta solución. Solucione el problema del doble clic y la ventana emergente fantasma:

$(document).on("shown.bs.popover",'[data-toggle="popover"]', function(){
    $(this).attr('someattr','1');
});
$(document).on("hidden.bs.popover",'[data-toggle="popover"]', function(){
    $(this).attr('someattr','0');
});
$(document).on('click', function (e) {
    $('[data-toggle="popover"],[data-original-title]').each(function () {
        //the 'is' for buttons that trigger popups
        //the 'has' for icons within a button that triggers a popup
        if (!$(this).is(e.target) && $(this).has(e.target).length === 0 && $('.popover').has(e.target).length === 0) {
            if($(this).attr('someattr')=="1"){
                $(this).popover("toggle");
            }
        }
    });
});
mattdlockyer avatar Feb 13 '2013 15:02 mattdlockyer
$('html').on('mouseup', function(e) {
    if(!$(e.target).closest('.popover').length) {
        $('.popover').each(function(){
            $(this.previousSibling).popover('hide');
        });
    }
});

Esto cierra todas las ventanas emergentes si hace clic en cualquier lugar excepto en una ventana emergente.

ACTUALIZACIÓN para Bootstrap 4.1

$("html").on("mouseup", function (e) {
    var l = $(e.target);
    if (l[0].className.indexOf("popover") == -1) {
        $(".popover").each(function () {
            $(this).popover("hide");
        });
    }
});
user28490 avatar Mar 27 '2013 21:03 user28490

La versión más simple y a prueba de fallas , funciona con cualquier versión de arranque.

Demostración: http://jsfiddle.net/guya/24mmM/

Demostración 2: No descartar al hacer clic dentro del contenido emergente http://jsfiddle.net/guya/fjZja/

Demostración 3: múltiples ventanas emergentes: http://jsfiddle.net/guya/6YCjW/


Simplemente llamar a esta línea descartará todos los popovers:

$('[data-original-title]').popover('hide');

Descarte todas las ventanas emergentes al hacer clic afuera con este código:

$('html').on('click', function(e) {
  if (typeof $(e.target).data('original-title') == 'undefined') {
    $('[data-original-title]').popover('hide');
  }
});

El fragmento de arriba adjunta un evento de clic en el cuerpo. Cuando el usuario hace clic en una ventana emergente, se comportará normalmente. Cuando el usuario hace clic en algo que no es una ventana emergente, se cerrarán todas las ventanas emergentes.

También funcionará con ventanas emergentes que se inician con Javascript, a diferencia de otros ejemplos que no funcionarán. (ver la demostración)

Si no desea descartar al hacer clic dentro del contenido de la ventana emergente, use este código (consulte el enlace a la segunda demostración):

$('html').on('click', function(e) {
  if (typeof $(e.target).data('original-title') == 'undefined' && !$(e.target).parents().is('.popover.in')) {
    $('[data-original-title]').popover('hide');
  }
});
guya avatar Oct 28 '2013 15:10 guya

Ninguna de las supuestas soluciones más votadas funcionó correctamente para mí. Cada uno genera un error cuando después de abrir y cerrar (haciendo clic en otros elementos) la ventana emergente por primera vez, no se abre nuevamente, hasta que haga dos clics en el enlace de activación en lugar de uno.

Así que lo modifiqué ligeramente:

$(document).on('click', function (e) {
    var
        $popover,
        $target = $(e.target);

    //do nothing if there was a click on popover content
    if ($target.hasClass('popover') || $target.closest('.popover').length) {
        return;
    }

    $('[data-toggle="popover"]').each(function () {
        $popover = $(this);

        if (!$popover.is(e.target) &&
            $popover.has(e.target).length === 0 &&
            $('.popover').has(e.target).length === 0)
        {
            $popover.popover('hide');
        } else {
            //fixes issue described above
            $popover.popover('toggle');
        }
    });
})
Anton Sergeyev avatar Nov 27 '2015 08:11 Anton Sergeyev

Con bootstrap 2.3.2 puedes configurar el disparador para 'enfocar' y simplemente funciona:

$('#el').popover({trigger:'focus'});
periklis avatar Sep 20 '2013 06:09 periklis