jQuery UI - Fechar diálogo quando clicado fora

113

Eu tenho um jQuery UI Dialog que é exibido quando elementos específicos são clicados. Gostaria de fechar a caixa de diálogo se ocorrer um clique em qualquer lugar que não seja nesses elementos de acionamento ou na própria caixa de diálogo.

Este é o código para abrir a caixa de 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');
    });*/
});

Se eu remover o comentário da última parte, a caixa de diálogo nunca será aberta. Presumo que seja porque o mesmo clique que abre a caixa de diálogo está fechando-a novamente.


Nota de código de trabalho final
: Isso está usando o plugin jQuery de eventos externos

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

Respostas:

31

Confira o plugin jQuery Outside Events

Permite que você faça:

$field_hint.bind('clickoutside',function(){
    $field_hint.dialog('close');
});
PetersenDidIt
fonte
Estou obtendo o mesmo comportamento, pois a dica não será exibida quando os elementos $ ('. Hint') forem clicados. Esses elementos estão 'fora' do diálogo.
Sonny,
Você só se preocupa com o clique externo se a caixa de diálogo estiver aberta. Portanto, vincule-o apenas depois de abri-lo.
PetersenDidIt
3
Li em outro lugar sobre a filtragem com base no evento e isso resolveu o problema: groups.google.com/group/jquery-ui/msg/a880d99138e1e80d
Sonny
A caixa de diálogo é reutilizada várias vezes no documento, então eu teria que encontrar uma maneira de desvincular ao fechar a caixa de diálogo. Acho que a filtragem é uma solução mais simples.
Sonny,
159

Desculpe arrastar isso depois de tanto tempo, mas usei o abaixo. Quaisquer desvantagens? Veja a função aberta ...

$("#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
fonte
18
Na verdade, isso só funcionará se a janela da interface do usuário for modal. Bem útil se você deseja fechar um diálogo modal
stumac85 01 de
37
Muito agradável. Acabei de alterá-lo para que não precise definir a referência de ID explicitamente:$('.ui-widget-overlay').bind('click', function () { $(this).siblings('.ui-dialog').find('.ui-dialog-content').dialog('close'); });
James McCormack
1
Eu gosto deste. Existe um caso em que você não deseja que seja modal, mas ainda deseja clicar fora para fechar? Não faz sentido para mim (acho que com modal você perde pairar sobre os elementos externos / inferiores).
Nick Spacek
3
@NickSpacek - Quando não é modal, posso definir o foco para um campo, abrir uma nova caixa de diálogo, etc. com apenas um clique. Com um diálogo modal, eu teria que usar dois cliques: um para fechá-lo e outro para fazer a próxima ação.
Sonny,
1
Obrigado! Você também pode aproveitar as vantagens do jQuery live bubbling. $ ('body'). on ('click', '.ui-widget-overlay', fechar);
Quang Van
78

Esqueça o uso de outro plugin:

Aqui estão três métodos para fechar uma caixa de diálogo da IU do jquery ao clicar fora do popin:

Se a caixa de diálogo for modal / tiver sobreposição de fundo: 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');
            })
        }
    });
}); 

Se a caixa de diálogo for não 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 2 de diálogo não modal: 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
fonte
2
Ótimo! Alterei ligeiramente a função de opção de abertura para diálogo modal, portanto, não há necessidade de nomear explicitamente o elemento. open : function () { $('.ui-widget-overlay').on('click', function () { $(this).parents("body").find(".ui-dialog-content").dialog("close"); }); }
meridius
Observe que, para a solução nº 2, .is ('. Ui-dialog, a') deve ser alterado para .is ('. Ui-dialog, qualquer que sejaYouClickOnToOpenTheDialog')
personne3000
@Jason por causa da vírgula, acho que esta linha está realmente dizendo "não o ui-dialog ou qualquer link na página". Se eu alterar o link "Abrir caixa de diálogo" em seu exemplo para <span>, a caixa de diálogo será fechada imediatamente após a abertura, quando o evento de janela for disparado por último, por isso acho que você precisa excluir o item em que clica para abrir o diálogo. Não entendo por que você precisa fazer referência a links na caixa de diálogo.
personne3000
@ personne3000 - na verdade, você está certo sobre o contexto, que o seletor está escolhendo os dois. Estou tentando lembrar por que adicionei isso, já que devo ter um motivo específico que não estou lembrando no momento.
Jason
@Jason para evitar conflitos com várias caixas de diálogo, você pode usar eventos com namespaceclick.myNamespace
Christophe Roussy
17

Basta adicionar este script global, que fecha todos os diálogos modais apenas clicando fora deles.

$(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
fonte
Não estou usando um diálogo modal. A resposta aqui com mais votos positivos também é para diálogos modais.
Sonny
Ao usar a mesma caixa de diálogo mais de uma vez na mesma página, este é o único caminho a seguir, pois só funcionará uma vez se você vinculá-lo à função abrir. Obrigado por esta ótima idéia!
MaDaHoPe de
aqui está o meu:$(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 o código acima em ação.

jk.
fonte
Vou dar uma olhada nisso. Obrigado Jen!
Sonny
8

Tive que fazer duas partes. Primeiro, o manipulador de cliques externo:

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

Isso chama dialog('close')a ui-dialog-contentclasse genérica e, portanto, fechará todos os diálogos se o clique não tiver origem em um. Também funcionará com diálogos modais, uma vez que a sobreposição não faz parte da .ui-dialogcaixa.

O problema é:

  1. A maioria das caixas de diálogo é criada por causa de cliques fora de uma caixa de diálogo
  2. Esse manipulador é executado depois que esses cliques criam uma caixa de diálogo e chegam ao documento, de modo que os fecha imediatamente.

Para corrigir isso, tive que adicionar stopPropagation a esses gerenciadores de clique:

moreLink.on('click', function (e) {
    listBox.dialog();
    e.stopPropagation(); //Don't trigger the outside click handler
});
Jerph
fonte
Isso parece mais simples do que a solução que estou usando. Eu terei que experimentar.
Sonny
Esta é a solução que pensei em mim mesmo, mas a minha é $('body').on('click', '.ui-widget-overlay', function () { $('#myDialog').dialog('close'); });
curta
5

Esta questão é um pouco antiga, mas caso alguém queira fechar uma caixa de diálogo que NÃO é modal quando o usuário clica em algum lugar, você pode usar isso que tirei do plugin JQuery UI Multiselect . A principal vantagem é que o clique não é "perdido" (se o usuário quiser clicar em um link ou botão, a ação está concluída).

$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
fonte
Tive que entrar var $dialog = $(this).dialog('widget');no manipulador de eventos on-click
Stefan Haberl
1
@Melanie, acho que sua solução é mais aplicável do que outras. Um cara criou um plugin para 'jqui dialog' baseado em sua abordagem - js no github
resnyanskiy
5

Você pode fazer isso sem usar nenhum plug-in 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");
            });
        }
    });

Aqui, $ diálogo é o diálogo. Basicamente, o que estamos fazendo é obter o último widget de sobreposição sempre que esta caixa de diálogo for aberta e vincular um manipulador de cliques a essa sobreposição para fechar $ diálogo sempre que clicar na sobreposição.

GuruKay
fonte
Acho que isso é semelhante a outras soluções para um diálogo modal. Minha pergunta era para diálogos não modais.
Sonny
5

não há necessidade do plugin de eventos externos ...

basta adicionar um manipulador de eventos ao div .ui-widget-overlay:

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

apenas certifique-se de que qualquer seletor que você usou para a caixa de diálogo da interface do usuário do jQuery também é chamado para fechá-la .. ou seja, # ui-dialog-selector-goes-here

Jonathan Marzullo
fonte
Várias soluções para fechar diálogos modais já foram propostas. Minha caixa de diálogo não é modal e, portanto, não tem sobreposição.
Sonny de
Em seguida, basta vincular o evento click à tag body ou envoltório div e usá-lo como gatilho do evento click, em vez do modal.
Jonathan Marzullo
Sim. Isso é essencialmente o que minha solução faz. Ele também deve excluir cliques na caixa de diálogo.
Sonny
3

Isso não usa jQuery UI, mas usa jQuery e pode ser útil para aqueles que não estão usando jQuery UI por qualquer motivo. Faça assim:

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

$(document).ready(function(){

  showDialog();    

});

Assim, depois de mostrar uma caixa de diálogo, adiciono um manipulador de clique que procura apenas o primeiro clique em qualquer coisa.

Agora, seria melhor se eu pudesse fazer com que ele ignorasse os cliques em qualquer coisa em #dialog e seu conteúdo, mas quando tentei trocar $ ('*') por $ (': not ("# diálogo, # diálogo *") '), ele ainda detectou #dialog cliques.

De qualquer forma, eu estava usando isso puramente para uma mesa de luz de fotos, então funcionou bem para esse propósito.

Volomike
fonte
2

Os exemplos fornecidos usam uma caixa de diálogo com id '#dialog', eu precisava de uma solução que fechasse qualquer caixa de 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');
        })
    }
});

Agradeço ao meu colega Youri Arkesteijn pela sugestão de uso de protótipo.

David van der Tuijn
fonte
2

Este é o único método que funcionou para mim para meu diálogo NÃO 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 o crédito vai para o eixo
Clique fora da caixa de diálogo não modal para fechar

Colin
fonte
1

Eu uso essa solução com base em uma postada aqui:

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

Eu tive o mesmo problema ao fazer a visualização modal em uma página. Depois de muito pesquisar no Google, achei essa solução muito útil. Com o evento e o alvo, ele verifica onde o clique aconteceu e, dependendo disso, aciona a ação ou não faz nada.

Site da biblioteca de trechos 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
fonte
0

É simples, na verdade você não precisa de nenhum plug-in, apenas do jquery ou você pode fazer isso com um javascript simples.

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

Eu não acho que encontrar coisas de diálogo usando $ ('. Any-selector') de todo o DOM seja tão brilhante.

Experimentar

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

Você está realmente obtendo a sobreposição da instância de diálogo à qual ela pertence, as coisas nunca darão errado desta maneira.

menino mau
fonte
Isso é para um diálogo modal? Meu OP é sobre não modal, então não há sobreposição.
Sonny
0

Com o código a seguir, você pode simular um clique no botão 'fechar' da caixa de diálogo (altere a string 'MY_DIALOG' pelo nome de sua própria caixa de diálogo)

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

Código inteligente: estou usando o seguinte código para que tudo permaneça claro e legível. o corpo externo fechará a caixa de diálogo.

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

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

Acabei usando este código que deve funcionar em qualquer caixa de diálogo aberta na página, ignora cliques nas dicas de ferramentas e limpa os recursos da caixa de diálogo que está sendo fechada também.


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