jQuery UI - Cerrar cuadro de diálogo cuando se hace clic en el exterior

113

Tengo un diálogo de interfaz de usuario de jQuery que se muestra cuando se hace clic en elementos específicos. Me gustaría cerrar el cuadro de diálogo si se produce un clic en cualquier lugar que no sea en los elementos desencadenantes o en el cuadro de diálogo en sí.

Aquí está el código para abrir el diálogo:

$(document).ready(function() {
    var $field_hint = $('<div></div>')
        .dialog({
            autoOpen: false,
            minHeight: 50,
            resizable: false,
            width: 375
        });

    $('.hint').click(function() {
        var $hint = $(this);
        $field_hint.html($hint.html());
        $field_hint.dialog('option', 'position', [162, $hint.offset().top + 25]);
        $field_hint.dialog('option', 'title', $hint.siblings('label').html());
        $field_hint.dialog('open');
    });
    /*$(document).click(function() {
        $field_hint.dialog('close');
    });*/
});

Si quito el comentario de la última parte, el cuadro de diálogo nunca se abre. Supongo que es porque el mismo clic que abre el cuadro de diálogo lo cierra nuevamente.


Nota final sobre el código de trabajo
: se utiliza el complemento de eventos externos de jQuery

$(document).ready(function() {
    // dialog element to .hint
    var $field_hint = $('<div></div>')
            .dialog({
                autoOpen: false,
                minHeight: 0,
                resizable: false,
                width: 376
            })
            .bind('clickoutside', function(e) {
                $target = $(e.target);
                if (!$target.filter('.hint').length
                        && !$target.filter('.hintclickicon').length) {
                    $field_hint.dialog('close');
                }
            });

    // attach dialog element to .hint elements
    $('.hint').click(function() {
        var $hint = $(this);
        $field_hint.html('<div style="max-height: 300px;">' + $hint.html() + '</div>');
        $field_hint.dialog('option', 'position', [$hint.offset().left - 384, $hint.offset().top + 24 - $(document).scrollTop()]);
        $field_hint.dialog('option', 'title', $hint.siblings('label').html());
        $field_hint.dialog('open');
    });

    // trigger .hint dialog with an anchor tag referencing the form element
    $('.hintclickicon').click(function(e) {
        e.preventDefault();
        $($(this).get(0).hash + ' .hint').trigger('click');
    });
});
Hijo
fuente

Respuestas:

31

Revisar la complemento de eventos externos de jQuery

Te deja hacer:

$field_hint.bind('clickoutside',function(){
    $field_hint.dialog('close');
});
PetersenDidIt
fuente
Tengo el mismo comportamiento, ya que la sugerencia no se mostrará cuando se haga clic en los elementos $ ('. Hint'). Esos elementos están "fuera" del diálogo.
Sonny
Solo le importa el clic exterior si el diálogo está abierto. Así que solo átalo después de abrirlo.
PetersenDidIt
3
Leí en otro lugar sobre el filtrado basado en el evento, y eso resolvió el problema: groups.google.com/group/jquery-ui/msg/a880d99138e1e80d
Sonny
El cuadro de diálogo se reutiliza varias veces en el documento, por lo que tendría que tener una forma de desvincularlo al cerrar el cuadro de diálogo. Creo que el filtrado es una solución más sencilla.
Sonny
159

Lamento arrastrar esto después de tanto tiempo, pero usé el siguiente. ¿Alguna desventaja? Ver la función abierta ...

$("#popup").dialog(
{
    height: 670,
    width: 680,
    modal: true,
    autoOpen: false,
    close: function(event, ui) { $('#wrap').show(); },
    open: function(event, ui) 
    { 
        $('.ui-widget-overlay').bind('click', function()
        { 
            $("#popup").dialog('close'); 
        }); 
    }
});
stumac85
fuente
18
En realidad, esto solo funcionará si la ventana de la interfaz de usuario es modal. Muy útil si desea cerrar un diálogo modal
stumac85
37
Muy agradable. Simplemente lo cambié a esto para no tener que establecer la referencia de ID explícitamente:$('.ui-widget-overlay').bind('click', function () { $(this).siblings('.ui-dialog').find('.ui-dialog-content').dialog('close'); });
James McCormack
1
Me gusta este. ¿Hay algún caso en el que no desee que sea modal pero aún desea hacer clic fuera para cerrar? No tiene sentido para mí (supongo que con modal se pierde flotando en los elementos exteriores / inferiores).
Nick Spacek
3
@NickSpacek: cuando no es modal, puedo establecer el foco en un campo, abrir un nuevo cuadro de diálogo, etc. con solo un clic. Con un diálogo modal, tendría que usar dos clics: uno para cerrarlo y otro para realizar la siguiente acción.
Sonny
1
¡Gracias! También puede aprovechar el burbujeo en vivo de jQuery. $ ('cuerpo'). on ('clic', '.ui-widget-overlay', cerrar);
Quang Van
78

Olvídese de usar otro complemento:

Aquí hay 3 métodos para cerrar un diálogo de interfaz de usuario de jquery al hacer clic fuera de la ventana emergente:

Si el cuadro de diálogo es modal / tiene una superposición de fondo: http://jsfiddle.net/jasonday/6FGqN/

jQuery(document).ready(function() {
    jQuery("#dialog").dialog({
        bgiframe: true,
        autoOpen: false,
        height: 100,
        modal: true,
        open: function(){
            jQuery('.ui-widget-overlay').bind('click',function(){
                jQuery('#dialog').dialog('close');
            })
        }
    });
}); 

Si el diálogo no es modal Método 1: método 1: http://jsfiddle.net/jasonday/xpkFf/

 // Close Pop-in If the user clicks anywhere else on the page
                     jQuery('body')
                      .bind(
                       'click',
                       function(e){
                        if(
                         jQuery('#dialog').dialog('isOpen')
                         && !jQuery(e.target).is('.ui-dialog, a')
                         && !jQuery(e.target).closest('.ui-dialog').length
                        ){
                         jQuery('#dialog').dialog('close');
                        }
                       }
                      );

Método de diálogo no modal 2: http://jsfiddle.net/jasonday/eccKr/

  $(function() {
            $( "#dialog" ).dialog({
                autoOpen: false, 
                minHeight: 100,
                width: 342,
                draggable: true,
                resizable: false,
                modal: false,
                closeText: 'Close',
                  open: function() {
                      closedialog = 1;
                      $(document).bind('click', overlayclickclose);
                  },
                  focus: function() {
                      closedialog = 0;
                  },
                  close: function() {
                      $(document).unbind('click');
                  }



        });

         $('#linkID').click(function() {
            $('#dialog').dialog('open');
            closedialog = 0;
        });

         var closedialog;

          function overlayclickclose() {
              if (closedialog) {
                  $('#dialog').dialog('close');
              }

              //set to one because click on dialog box sets to zero
              closedialog = 1;
          }


  });
Jason
fuente
2
¡Excelente! Cambié ligeramente la función de opción abierta para el diálogo modal, por lo que no es necesario nombrar explícitamente el elemento. open : function () { $('.ui-widget-overlay').on('click', function () { $(this).parents("body").find(".ui-dialog-content").dialog("close"); }); }
Meridius
Tenga en cuenta que para la solución n. ° 2, .is ('. Ui-dialog, a') debe cambiarse a .is ('. Ui-dialog, anythingYouClickOnToOpenTheDialog')
personne3000
@Jason debido a la coma, creo que esta línea en realidad dice "no es el diálogo de interfaz de usuario, ni ningún enlace en la página". Si cambio el enlace "Abrir cuadro de diálogo" en su ejemplo a <span>, el cuadro de diálogo se cierra inmediatamente después de abrirse, ya que el evento de ventana se activa por última vez, por lo que creo que debe excluir el elemento en el que hace clic para abrir el diálogo. No entiendo por qué necesitarías hacer referencia a los enlaces en el cuadro de diálogo.
personne3000
@ personne3000 - en realidad tiene razón sobre el contexto, que el selector está eligiendo ambos. Estoy tratando de recordar por qué agregué eso, ya que debo haber tenido una razón específica que no recuerdo en este momento.
Jason
@Jason para evitar conflictos con múltiples diálogos, puede usar eventos de espacio de nombresclick.myNamespace
Christophe Roussy
17

Simplemente agregue este script global, que cierra todos los diálogos modales simplemente haciendo clic fuera del sitio.

$(document).ready(function()
{
    $(document.body).on("click", ".ui-widget-overlay", function()
    {
        $.each($(".ui-dialog"), function()
        {
            var $dialog;
            $dialog = $(this).children(".ui-dialog-content");
            if($dialog.dialog("option", "modal"))
            {
                $dialog.dialog("close");
            }
        });
    });;
});
Michele Locati
fuente
No estoy usando un diálogo modal. La respuesta aquí con la mayor cantidad de votos positivos es también para los diálogos modales.
Sonny
Cuando se usa el mismo cuadro de diálogo más de una vez en la misma página, esta es la única forma de hacerlo, ya que solo funcionará una vez si lo vincula en la función abierta. Gracias por esta gran idea!
MaDaHoPe
aquí está el mío:$(document).on('click', '.ui-widget-overlay', function() { $('#'+$('.ui-dialog-content')[0].id).dialog('close'); });
mr5
10
$(".ui-widget-overlay").click (function () {
    $("#dialog-id").dialog( "close" );
});

Fiddle mostrando el código anterior en acción.

jk.
fuente
Lo echaré un vistazo. ¡Gracias Jen!
Sonny
8

Tuve que hacer dos partes. Primero, el controlador de clic externo:

$(document).on('click', function(e){
    if ($(".ui-dialog").length) {
        if (!$(e.target).parents().filter('.ui-dialog').length) {
            $('.ui-dialog-content').dialog('close');
        }
    }
}); 

Esto llama dialog('close')a la ui-dialog-contentclase genérica y, por lo tanto, cerrará todos los cuadros de diálogo si el clic no se originó en uno. También funcionará con cuadros de diálogo modales, ya que la superposición no es parte del.ui-dialog cuadro.

El problema es:

  1. La mayoría de los cuadros de diálogo se crean debido a clics fuera de un cuadro de diálogo
  2. Este controlador se ejecuta después de que esos clics hayan creado un diálogo y hayan aparecido en el documento, por lo que los cierra inmediatamente.

Para solucionar esto, tuve que agregar stopPropagation a esos controladores de clic:

moreLink.on('click', function (e) {
    listBox.dialog();
    e.stopPropagation(); //Don't trigger the outside click handler
});
Jerph
fuente
Esto suena más simple que la solución que estoy usando. Tendré que probarlo.
Sonny
Esta es la solución que pensé en mí mismo, pero la mía es de una sola línea:$('body').on('click', '.ui-widget-overlay', function () { $('#myDialog').dialog('close'); });
styfle
5

Esta pregunta es un poco antigua, pero en caso de que alguien quiera cerrar un cuadro de diálogo que NO es modal cuando el usuario hace clic en algún lugar, puede usar esto que tomé del complemento JQuery UI Multiselect . La principal ventaja es que el clic no se "pierde" (si el usuario desea hacer clic en un enlace o un botón, la acción se realiza).

$myselector.dialog({
            title: "Dialog that closes when user clicks outside",
            modal:false,
            close: function(){
                        $(document).off('mousedown.mydialog');
                    },
            open: function(event, ui) { 
                    var $dialog = $(this).dialog('widget');
                    $(document).on('mousedown.mydialog', function(e) {
                        // Close when user clicks elsewhere
                        if($dialog.dialog('isOpen') && !$.contains($myselector.dialog('widget')[0], e.target)){
                            $myselector.dialog('close');
                        }            
                    });
                }                    
            });
Melanie
fuente
Tuve que moverme var $dialog = $(this).dialog('widget');dentro del controlador de eventos al hacer clic
Stefan Haberl
1
@Melanie, creo que tu solución es más aplicable que otras. Un chico creó el complemento para 'jqui dialog' basado en su enfoque - js en github
resnyanskiy
5

Puede hacer esto sin utilizar ningún complemento adicional

var $dialog= $(document.createElement("div")).appendTo(document.body);
    var dialogOverlay;

    $dialog.dialog({
        title: "Your title",
        modal: true,
        resizable: true,
        draggable: false,
        autoOpen: false,
        width: "auto",
        show: "fade",
        hide: "fade",
        open:function(){
            $dialog.dialog('widget').animate({
                width: "+=300", 
                left: "-=150"
            });

//get the last overlay in the dom
            $dialogOverlay = $(".ui-widget-overlay").last();
//remove any event handler bound to it.
            $dialogOverlay.unbind();
            $dialogOverlay.click(function(){
//close the dialog whenever the overlay is clicked.
                $dialog.dialog("close");
            });
        }
    });

Aquí $ dialog es el diálogo. Básicamente, lo que estamos haciendo es obtener el último widget de superposición cada vez que se abre este cuadro de diálogo y vincular un controlador de clic a esa superposición para cerrar $ dialog cuando se hace clic en la superposición.

GuruKay
fuente
Creo que esto es similar a otras soluciones para un diálogo modal. Mi pregunta era para los diálogos no modales.
Sonny
5

no es necesario el complemento de eventos externos ...

simplemente agregue un controlador de eventos al div .ui-widget-overlay:

jQuery(document).on('click', 'body > .ui-widget-overlay', function(){
     jQuery("#ui-dialog-selector-goes-here").dialog("close");
     return false;
});

solo asegúrese de que cualquier selector que utilizó para el diálogo de la interfaz de usuario de jQuery, también se llame para cerrarlo .. es decir, # ui-dialog-selector-va-aquí

Jonathan Marzullo
fuente
Ya se han propuesto varias soluciones para cerrar los diálogos modales. Mi diálogo no es modal y, por lo tanto, no tiene superposición.
Sonny
Entonces simplemente enlaza el evento de clic a la etiqueta del cuerpo o al contenedor div y lo usa como su activador de evento de clic, en lugar del modal.
Jonathan Marzullo
Si. Eso es esencialmente lo que hace mi solución. También tiene que excluir los clics dentro del cuadro de diálogo.
Sonny
3

Esto no usa jQuery UI, pero usa jQuery, y puede ser útil para aquellos que no usan jQuery UI por cualquier motivo. Hazlo así:

function showDialog(){
  $('#dialog').show();
  $('*').on('click',function(e){
    $('#zoomer').hide();
  });
}

$(document).ready(function(){

  showDialog();    

});

Entonces, una vez que he mostrado un cuadro de diálogo, agrego un controlador de clic que solo busca el primer clic en cualquier cosa.

Ahora, sería mejor si pudiera hacer que ignorara los clics en cualquier cosa en #dialog y su contenido, pero cuando intenté cambiar $ ('*') con $ (': not ("# dialog, # dialog *") '), aún detectó # clics de diálogo.

De todos modos, estaba usando esto únicamente para una caja de luz de fotos, así que funcionó bien para ese propósito.

Volomike
fuente
2

Los ejemplos dados usan un diálogo con id '#dialog', necesitaba una solución que cerrara cualquier diálogo:

$.extend($.ui.dialog.prototype.options, {
    modal: true,
    open: function(object) {
        jQuery('.ui-widget-overlay').bind('click', function() {              
            var id = jQuery(object.target).attr('id');
            jQuery('#'+id).dialog('close');
        })
    }
});

Gracias a mi colega Youri Arkesteijn por la sugerencia de usar el prototipo.

David van der Tuijn
fuente
2

Este es el único método que me funcionó para mi cuadro de diálogo NO MODAL

$(document).mousedown(function(e) {
    var clicked = $(e.target); // get the element clicked
    if (clicked.is('#dlg') || clicked.parents().is('#dlg') || clicked.is('.ui-dialog-titlebar')) {
        return; // click happened within the dialog, do nothing here
    } else { // click was outside the dialog, so close it
        $('#dlg').dialog("close");
    }
});

Todo el crédito va a Axle
Haga clic fuera del cuadro de diálogo no modal para cerrar

Colin
fuente
1

Utilizo esta solución basada en una publicada aquí:

var g_divOpenDialog = null;
function _openDlg(l_d) {

  // http://stackoverflow.com/questions/2554779/jquery-ui-close-dialog-when-clicked-outside
  jQuery('body').bind(
   'click',
   function(e){
    if(
      g_divOpenDialog!=null 
      && !jQuery(e.target).is('.ui-dialog, a')
      && !jQuery(e.target).closest('.ui-dialog').length
    ){
      _closeDlg();
    }
   }
  );

  setTimeout(function() {
    g_divOpenDialog = l_d;
    g_divOpenDialog.dialog();
  }, 500);
}
function _closeDlg() {
  jQuery('body').unbind('click');
  g_divOpenDialog.dialog('close');
  g_divOpenDialog.dialog('destroy');
  g_divOpenDialog = null;
}
Alejo
fuente
1

Tuve el mismo problema al hacer la vista previa modal en una página. Después de mucho buscar en Google, encontré esta solución muy útil. Con evento y destino, está comprobando dónde ocurrió el clic y, dependiendo de ello, activa la acción o no hace nada.

Sitio de la biblioteca de fragmentos de código

$('#modal-background').mousedown(function(e) {
var clicked = $(e.target);  
if (clicked.is('#modal-content') || clicked.parents().is('#modal-content')) 
    return; 
} else {  
 $('#modal-background').hide();
}
});
Nikola Mirković - Johnny
fuente
0

Es simple, en realidad no necesita ningún complemento, solo jquery o puede hacerlo con un simple javascript.

$('#dialog').on('click', function(e){
  e.stopPropagation();
});
$(document.body).on('click', function(e){
  master.hide();
});
Rzasgal
fuente
0

No creo que encontrar cosas de diálogo usando $ ('. Any-selector') de todo el DOM sea tan brillante.

Tratar

$('<div />').dialog({
    open: function(event, ui){
        var ins = $(this).dialog('instance');
        var overlay = ins.overlay;
        overlay.off('click').on('click', {$dialog: $(this)}, function(event){
            event.data.$dialog.dialog('close');
        });
    }
});

Realmente está obteniendo la superposición de la instancia de diálogo a la que pertenece, las cosas nunca saldrán mal de esta manera.

chico malo
fuente
¿Esto es para un diálogo modal? Mi OP es no modal, por lo que no hay superposición.
Sonny
0

Con el siguiente código, puede simular un clic en el botón 'cerrar' del diálogo (cambie la cadena 'MY_DIALOG' por el nombre de su propio diálogo)

$("div[aria-labelledby='ui-dialog-title-MY_DIALOG'] div.ui-helper-clearfix a.ui-dialog-titlebar-close")[0].click();
perkas
fuente
0

Código inteligente: estoy usando el siguiente código para que todo quede claro y legible. out side body cerrará el cuadro de diálogo.

$(document).ready(function () {
   $('body').on('click', '.ui-widget-overlay', closeDialogBox);
});

function closeDialogBox() {
    $('#dialog-message').dialog('close');
}
Farid Abbas
fuente
0

Terminé usando este código que debería funcionar en cualquier cuadro de diálogo abierto en la página, ignora los clics en la información sobre herramientas y también limpia los recursos del cuadro de diálogo que se cierra.


        $(document).mousedown(function(e) {
            var clicked = $(e.target); // get the element clicked
            if (clicked.is('.ui-dialog-content, .ui-dialog-titlebar, .ui-tooltip') || clicked.parents().is('.ui-dialog-content, .ui-dialog-titlebar, .ui-tooltip')) {
                return; // click happened within the dialog, do nothing here
            } else { // click was outside the dialog, so close it
                $('.ui-dialog-content').dialog("close");
                $('.ui-dialog-content').dialog("destroy");
                $('.ui-dialog-content').detach();

            }
        });
Kevin Baragona
fuente