jQuery UI - Fermer la boîte de dialogue lorsque vous cliquez à l'extérieur


113

J'ai une boîte de dialogue d'interface utilisateur jQuery qui s'affiche lorsque l'utilisateur clique sur des éléments spécifiques. Je voudrais fermer la boîte de dialogue si un clic se produit ailleurs que sur ces éléments déclencheurs ou sur la boîte de dialogue elle-même.

Voici le code pour ouvrir la boîte de dialogue:

$(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 je décommente la dernière partie, la boîte de dialogue ne s'ouvre jamais. Je suppose que c'est parce que le même clic qui ouvre la boîte de dialogue la ferme à nouveau.


Note sur le code de travail final
: Ceci utilise le plugin jQuery Outside Events

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

Réponses:


31

Découvrez le plugin jQuery Outside Events

Vous permet de faire:

$field_hint.bind('clickoutside',function(){
    $field_hint.dialog('close');
});

J'obtiens le même comportement, en ce sens que le conseil ne s'affiche pas lorsque les éléments $ ('. Hint') sont cliqués. Ces éléments sont «en dehors» du dialogue.
Sonny

Vous ne vous souciez du clic extérieur que si la boîte de dialogue est ouverte. Alors ne le liez qu'après l'avoir ouvert.
PetersenDidIt

3
J'ai lu dans un autre endroit sur le filtrage basé sur l'événement, et cela a résolu le problème: groups.google.com/group/jquery-ui/msg/a880d99138e1e80d
Sonny

La boîte de dialogue est réutilisée plusieurs fois dans le document, je devrais donc avoir un moyen de dissocier lors de la fermeture de la boîte de dialogue. Je pense que le filtrage est une solution plus simple.
Sonny

159

Désolé de faire glisser cela après si longtemps, mais j'ai utilisé le ci-dessous. Des inconvénients? Voir la fonction ouverte ...

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

18
En fait, cela ne fonctionnera que si la fenêtre de l'interface utilisateur est modale. Bien utile si vous souhaitez fermer une boîte de dialogue modale
stumac85

37
Très agréable. Je viens de le changer pour cela, donc je n'ai pas eu à définir explicitement la référence d'identification:$('.ui-widget-overlay').bind('click', function () { $(this).siblings('.ui-dialog').find('.ui-dialog-content').dialog('close'); });
James McCormack

1
J'aime celui la. Y a-t-il un cas où vous ne voulez pas qu'il soit modal mais que vous voulez quand même cliquer à l'extérieur pour fermer? Cela n'a pas de sens pour moi (je suppose qu'avec le modal, vous perdez le survol des éléments extérieurs / inférieurs).
Nick Spacek

3
@NickSpacek - Lorsqu'il n'est pas modal, je peux définir le focus sur un champ, ouvrir une nouvelle boîte de dialogue, etc. en un seul clic. Avec une boîte de dialogue modale, je devrais utiliser deux clics: un pour le fermer et un pour faire l'action suivante.
Sonny

1
Merci! Vous pouvez également profiter du bullage en direct de jQuery. $ ('body'). on ('click', '.ui-widget-overlay', fermer);
Quang Van

78

Oubliez d'utiliser un autre plugin:

Voici 3 méthodes pour fermer une boîte de dialogue d'interface utilisateur jquery lorsque vous cliquez sur popin extérieur:

Si la boîte de dialogue est modale / a une superposition d'arrière-plan: 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 le dialogue n'est pas modal Méthode 1: méthode 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éthode de dialogue non modale 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;
          }


  });

2
Génial! J'ai légèrement modifié la fonction d'option ouverte pour le dialogue modal, il n'est donc pas nécessaire de nommer explicitement l'élément. open : function () { $('.ui-widget-overlay').on('click', function () { $(this).parents("body").find(".ui-dialog-content").dialog("close"); }); }
meridius

Notez que pour la solution n ° 2, .is ('. Ui-dialog, a') doit être remplacé par .is ('. Ui-dialog ,whatYouClickOnToOpenTheDialog')
personne3000

@Jason à cause de la virgule, je pense que cette ligne dit en fait "pas le dialogue de l'interface utilisateur, ni aucun lien dans la page". Si je change le lien "Ouvrir la boîte de dialogue" dans votre exemple en <span>, la boîte de dialogue se ferme immédiatement après son ouverture car l'événement de fenêtre est déclenché en dernier, c'est pourquoi je pense que vous devez exclure l'élément sur lequel vous cliquez pour ouvrir le dialogue. Je ne comprends pas pourquoi vous auriez besoin de référencer des liens dans la boîte de dialogue?
personne3000

@ personne3000 - en fait vous avez raison sur le contexte, que le sélecteur choisit les deux. J'essaie de me rappeler pourquoi j'ai ajouté cela, car j'ai dû avoir une raison spécifique dont je ne me souviens pas pour le moment.
Jason

@Jason pour éviter les conflits avec plusieurs dialogues, vous pouvez utiliser des événements d'espacement de nomsclick.myNamespace
Christophe Roussy

17

Ajoutez simplement ce script global, qui ferme toutes les boîtes de dialogue modales en cliquant simplement sur leur site.

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

Je n'utilise pas de boîte de dialogue modale. La réponse ici avec le plus de votes positifs est également pour les dialogues modaux.
Sonny

Lorsque vous utilisez la même boîte de dialogue plusieurs fois sur la même page, c'est la seule façon de procéder car elle ne fonctionnera qu'une seule fois si vous la liez dans la fonction ouverte. Merci pour cette bonne idée!
MaDaHoPe

voici le mien:$(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 montrant le code ci-dessus en action.


Je vais y jeter un œil. Merci Jen!
Sonny

8

J'ai dû faire deux parties. D'abord le gestionnaire de clics extérieur:

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

Cela fait appel dialog('close')à la ui-dialog-contentclasse générique , et fermera donc toutes les boîtes de dialogue si le clic ne provenait pas d'une seule. Cela fonctionnera également avec les boîtes de dialogue modales, car la superposition ne fait pas partie de la .ui-dialogboîte.

Le problème est:

  1. La plupart des boîtes de dialogue sont créées en raison de clics en dehors d'une boîte de dialogue
  2. Ce gestionnaire s'exécute une fois que ces clics ont créé une boîte de dialogue et remonté dans le document, de sorte qu'il les ferme immédiatement.

Pour résoudre ce problème, j'ai dû ajouter stopPropagation à ces gestionnaires de clics:

moreLink.on('click', function (e) {
    listBox.dialog();
    e.stopPropagation(); //Don't trigger the outside click handler
});

Cela semble plus simple que la solution que j'utilise. Je vais devoir l'essayer.
Sonny

C'est la solution que j'ai pensé de moi, mais la mienne est un one-liner:$('body').on('click', '.ui-widget-overlay', function () { $('#myDialog').dialog('close'); });
styfle

5

Cette question est un peu ancienne, mais au cas où quelqu'un voudrait fermer une boîte de dialogue qui n'est PAS modale lorsque l'utilisateur clique quelque part, vous pouvez utiliser celle que j'ai tirée du plugin JQuery UI Multiselect . Le principal avantage est que le clic n'est pas "perdu" (si l'utilisateur veut cliquer sur un lien ou un bouton, l'action est terminée).

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

Je devais me déplacer var $dialog = $(this).dialog('widget');dans le gestionnaire d'événements on-click
Stefan Haberl

1
@Melanie, je pense que votre solution est plus applicable que d'autres. Un gars a créé un plugin pour 'jqui dialog' basé sur votre approche - js sur github
resnyanskiy

5

Vous pouvez le faire sans utiliser de plug-in supplémentaire

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

Ici, $ dialog est le dialogue. Ce que nous faisons essentiellement est d'obtenir le dernier widget de superposition chaque fois que cette boîte de dialogue est ouverte et de lier un gestionnaire de clic à cette superposition pour fermer $ dialog à chaque fois que l'on clique sur la superposition.


Je pense que c'est similaire à d'autres solutions pour un dialogue modal. Ma question concernait les dialogues non modaux.
Sonny

5

pas besoin du plugin d'événements extérieurs ...

ajoutez simplement un gestionnaire d'événements à la div .ui-widget-overlay:

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

assurez-vous simplement que le sélecteur que vous avez utilisé pour la boîte de dialogue jQuery ui, est également appelé pour le fermer .. ie # ui-dialog-selector-going-here


Plusieurs solutions de fermeture des dialogues modaux ont déjà été proposées. Ma boîte de dialogue n'est pas modale et n'a donc pas de superposition.
Sonny

Ensuite, il vous suffit de lier l'événement de clic à la balise body ou à l'encapsuleur div et de l'utiliser comme déclencheur d'événement de clic, au lieu du modal.
Jonathan Marzullo

Oui. C'est essentiellement ce que fait ma solution. Il doit également exclure les clics dans la boîte de dialogue.
Sonny

3

Cela n'utilise pas l'interface utilisateur jQuery, mais utilise jQuery et peut être utile pour ceux qui n'utilisent pas l'interface utilisateur jQuery pour une raison quelconque. Faites-le comme ceci:

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

$(document).ready(function(){

  showDialog();    

});

Donc, une fois que j'ai montré une boîte de dialogue, j'ajoute un gestionnaire de clics qui ne recherche que le premier clic sur quoi que ce soit.

Maintenant, ce serait mieux si je pouvais le faire ignorer les clics sur n'importe quoi sur #dialog et son contenu, mais quand j'essayais de changer $ ('*') avec $ (': not ("# dialog, # dialog *") '), il a quand même détecté des clics #dialog.

Quoi qu'il en soit, je l'utilisais uniquement pour une lightbox photo, donc cela fonctionnait bien dans ce but.


2

Les exemples donnés utilisent une boîte de dialogue avec l'ID '#dialog', j'avais besoin d'une solution qui ferme toutes les boîtes de dialogue:

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

Merci à mon collègue Youri Arkesteijn pour la suggestion d'utiliser un prototype.


2

C'est la seule méthode qui a fonctionné pour moi pour ma boîte de dialogue NON-MODALE

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

Tout le mérite revient à Axle
Cliquez en dehors de la boîte de dialogue non modale pour fermer



1

J'utilise cette solution basée sur celle publiée ici:

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

1

J'ai eu le même problème lors de la création d'un aperçu modal sur une page. Après de nombreuses recherches sur Google, j'ai trouvé cette solution très utile. Avec l'événement et la cible, il vérifie où le clic s'est produit et, en fonction de cela, déclenche l'action ou ne fait rien.

Site de la bibliothèque d'extraits de code

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

0

C'est simple en fait, vous n'avez pas besoin de plugins, juste jquery ou vous pouvez le faire avec un simple javascript.

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

0

Je ne pense pas que trouver des dialogues en utilisant $ ('. Any-selector') de tout le DOM soit si brillant.

Essayer

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

Vous obtenez vraiment la superposition de l'instance de dialogue à laquelle elle appartient, les choses ne se passeront jamais de cette façon.


C'est pour un dialogue modal? Mon OP est non modal, donc il n'y a pas de superposition.
Sonny

0

Avec le code suivant, vous pouvez simuler un clic sur le bouton 'fermer' de la boîte de dialogue (changer la chaîne 'MY_DIALOG' pour le nom de votre propre boîte de dialogue)

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

0

Smart Code: J'utilise le code suivant pour que tout reste clair et lisible. à l'extérieur du corps fermera la boîte de dialogue.

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

function closeDialogBox() {
    $('#dialog-message').dialog('close');
}

0

J'ai fini par utiliser ce code qui devrait fonctionner sur toutes les boîtes de dialogue ouvertes sur la page, ignore les clics sur les info-bulles et nettoie également les ressources de la boîte de dialogue en cours de fermeture.


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

            }
        });
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.