Interfejs użytkownika jQuery - Zamknij okno dialogowe po kliknięciu na zewnątrz

113

Mam okno dialogowe interfejsu użytkownika jQuery, które jest wyświetlane po kliknięciu określonych elementów. Chciałbym zamknąć okno dialogowe, jeśli kliknięcie nastąpi w innym miejscu niż te elementy wyzwalające lub samo okno dialogowe.

Oto kod otwierający okno dialogowe:

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

Jeśli odkomentuję ostatnią część, okno dialogowe nigdy się nie otworzy. Zakładam, że dzieje się tak, ponieważ to samo kliknięcie, które otwiera okno dialogowe, powoduje jego ponowne zamknięcie.


Końcowy kod roboczy
Uwaga: to jest użycie wtyczki jQuery zdarzenia zewnętrzne

$(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');
    });
});
Synek
źródło

Odpowiedzi:

31

Sprawdź wtyczkę jQuery Outside Events

Pozwala:

$field_hint.bind('clickoutside',function(){
    $field_hint.dialog('close');
});
PetersenDidIt
źródło
Otrzymuję to samo zachowanie, ponieważ wskazówka nie zostanie wyświetlona po kliknięciu elementów $ ('. Hint'). Te elementy znajdują się „poza” oknem dialogowym.
Sonny
Dbasz tylko o kliknięcie na zewnątrz, jeśli okno dialogowe jest otwarte. Więc zwiąż go dopiero po otwarciu.
PetersenDidIt
3
Czytałem w innym miejscu o filtrowaniu opartym na zdarzeniu i to rozwiązało problem: groups.google.com/group/jquery-ui/msg/a880d99138e1e80d
Sonny
Okno dialogowe jest wielokrotnie używane w dokumencie, więc musiałbym mieć sposób na usunięcie wiązania podczas zamykania okna. Myślę, że filtrowanie jest prostszym rozwiązaniem.
Sonny
159

Przepraszam, że przeciągam to po tak długim czasie, ale użyłem poniższego. Jakieś wady? Zobacz funkcję open ...

$("#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
źródło
18
W rzeczywistości zadziała to tylko wtedy, gdy okno interfejsu użytkownika jest modalne. Przydatne, jeśli chcesz zamknąć okno dialogowe
stumac85
37
Bardzo dobrze. Po prostu zmieniłem to na to, więc nie musiałem jawnie ustawiać odniesienia ID:$('.ui-widget-overlay').bind('click', function () { $(this).siblings('.ui-dialog').find('.ui-dialog-content').dialog('close'); });
James McCormack,
1
Podoba mi się ten. Czy jest przypadek, w którym nie chcesz, aby był modalny, ale nadal chcesz kliknąć na zewnątrz, aby zamknąć? Nie ma to dla mnie sensu (myślę, że z modalem tracisz unoszenie się na zewnątrz / pod elementami).
Nick Spacek
3
@NickSpacek - Kiedy nie jest modalny, mogę ustawić fokus na pole, otworzyć nowe okno dialogowe itp. Za pomocą jednego kliknięcia. W oknie modalnym musiałbym użyć dwóch kliknięć: jednego do zamknięcia, a drugiego do wykonania następnej czynności.
Sonny
1
Dzięki! Możesz także skorzystać z propagacji jQuery na żywo. $ ('body'). on ('click', '.ui-widget-overlay', zamknij);
Quang Van
78

Zapomnij o używaniu innej wtyczki:

Oto 3 metody zamykania okna dialogowego interfejsu użytkownika jquery po kliknięciu poza popinem:

Jeśli okno dialogowe jest modalne / ma nakładkę w tle: 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');
            })
        }
    });
}); 

Jeśli okno dialogowe jest niemodalne Metoda 1: metoda 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');
                        }
                       }
                      );

Niemodalna metoda dialogu 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
źródło
2
Wspaniały! Nieznacznie zmieniłem funkcję opcji otwierania dla okna dialogowego modalnego, więc nie ma potrzeby jawnego nazwania elementu. open : function () { $('.ui-widget-overlay').on('click', function () { $(this).parents("body").find(".ui-dialog-content").dialog("close"); }); }
meridius
Zauważ, że dla rozwiązania nr 2, .is ('. Ui-dialog, a') musi zostać zmienione na .is ('. Ui-dialog, cokolwiekYouClickOnToOpenTheDialog')
personne3000
@Jason ze względu na przecinek, myślę, że w tym wierszu jest napisane „nie okno dialogowe interfejsu użytkownika ani żaden link na stronie”. Jeśli zmienię łącze „Otwórz okno dialogowe” w Twoim przykładzie na <span>, okno dialogowe zostanie zamknięte natychmiast po otwarciu, ponieważ zdarzenie okna jest wywoływane jako ostatnie, dlatego myślę, że musisz wykluczyć element, który kliknąłeś, aby otworzyć dialog. Nie rozumiem, dlaczego musisz odnosić się do linków w oknie dialogowym?
personne3000
@ personne3000 - właściwie masz rację co do kontekstu, że selektor wybiera oba. Próbuję sobie przypomnieć, dlaczego to dodałem, ponieważ musiałem mieć konkretny powód, którego w tej chwili nie pamiętam.
Jason
@Jason, aby uniknąć konfliktów z wieloma oknami dialogowymi, możesz użyć wydarzeń z przestrzenią nazwclick.myNamespace
Christophe Roussy
17

Po prostu dodaj ten globalny skrypt, który zamyka wszystkie okna dialogowe po prostu klikając je poza nimi.

$(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
źródło
Nie używam modalnego okna dialogowego. Odpowiedź z największą liczbą głosów pozytywnych dotyczy również okien dialogowych modalnych.
Sonny
Jeśli używasz tego samego okna dialogowego więcej niż raz na tej samej stronie, jest to jedyny sposób, ponieważ zadziała tylko raz, jeśli powiązasz go w funkcji otwierania. Dzięki za świetny pomysł!
MaDaHoPe
oto moje:$(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 pokazujący powyższy kod w akcji.

jk.
źródło
Rzucę okiem na to. Dzięki Jen!
Sonny
8

Musiałem zrobić dwie części. Najpierw zewnętrzny moduł obsługi kliknięcia:

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

Spowoduje to wywołanie klasy dialog('close')ogólnej ui-dialog-contenti zamknie wszystkie okna dialogowe, jeśli kliknięcie nie nastąpiło w żadnym z nich. Będzie działać również z modalnymi oknami dialogowymi, ponieważ nakładka nie jest częścią.ui-dialog pola.

Problemem jest:

  1. Większość okien dialogowych jest tworzona z powodu kliknięć poza oknem dialogowym
  2. Ten program obsługi jest uruchamiany po tym, jak te kliknięcia utworzyły okno dialogowe i przeszły do ​​dokumentu, więc natychmiast je zamyka.

Aby to naprawić, musiałem dodać stopPropagation do tych programów obsługi kliknięć:

moreLink.on('click', function (e) {
    listBox.dialog();
    e.stopPropagation(); //Don't trigger the outside click handler
});
Jerph
źródło
Wydaje się to prostsze niż rozwiązanie, którego używam. Będę musiał to wypróbować.
Sonny
To jest rozwiązanie, które pomyślałem o sobie, ale moje jest $('body').on('click', '.ui-widget-overlay', function () { $('#myDialog').dialog('close'); });
jednoliniowe
5

To pytanie jest trochę stare, ale w przypadku, gdy ktoś chce zamknąć okno dialogowe, które NIE jest modalne, gdy użytkownik gdzieś kliknie, możesz użyć tego, które wziąłem z wtyczki JQuery UI Multiselect . Główną zaletą jest to, że kliknięcie nie jest „gubione” (jeśli użytkownik chce kliknąć link lub przycisk, akcja jest wykonywana).

$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
źródło
Musiałem wejść var $dialog = $(this).dialog('widget');do programu obsługi zdarzeń on-click
Stefan Haberl
1
@Melanie, myślę, że twoje rozwiązanie jest bardziej odpowiednie niż inne. Jeden facet stworzył wtyczkę do „jqui dialog” w oparciu o twoje podejście - js at github
resnyanskiy
5

Możesz to zrobić bez używania dodatkowej wtyczki

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

Tutaj $ dialog jest oknem dialogowym. Zasadniczo robimy to, aby uzyskać ostatni widżet nakładki za każdym razem, gdy otworzy się to okno dialogowe, i powiązać moduł obsługi kliknięcia z tą nakładką, aby zamknąć okno dialogowe $ dialog za każdym razem, gdy nakładka zostanie kliknięta.

GuruKay
źródło
Myślę, że jest to podobne do innych rozwiązań dla dialogu modalnego. Moje pytanie dotyczyło okien dialogowych niemodalnych.
Sonny
5

nie ma potrzeby korzystania z wtyczki wydarzeń zewnętrznych ...

po prostu dodaj procedurę obsługi zdarzeń do elementu div .ui-widget-overlay:

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

po prostu upewnij się, że dowolny selektor, którego użyłeś w oknie dialogowym jQuery ui, jest również wywoływany, aby je zamknąć .. tj. # ui-dialog-selector-go-here

Jonathan Marzullo
źródło
Zaproponowano już kilka rozwiązań do zamykania dialogów modalnych. Moje okno dialogowe jest niemodalne i dlatego nie ma nakładki.
Sonny
Następnie wystarczy powiązać zdarzenie click z tagiem body lub opakowaniem elementu div i użyć go jako wyzwalacza zdarzenia kliknięcia, a nie modalnego.
Jonathan Marzullo
Tak. Zasadniczo to właśnie robi moje rozwiązanie. Musi również wykluczać kliknięcia w oknie dialogowym.
Sonny
3

To nie używa interfejsu użytkownika jQuery, ale używa jQuery i może być przydatne dla tych, którzy z jakiegokolwiek powodu nie używają interfejsu użytkownika jQuery. Zrób to tak:

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

$(document).ready(function(){

  showDialog();    

});

Po wyświetleniu okna dialogowego dodaję moduł obsługi kliknięcia, który szuka tylko pierwszego kliknięcia.

Teraz byłoby lepiej, gdybym mógł zmusić go do ignorowania kliknięć czegokolwiek w #dialog i jego zawartości, ale kiedy próbowałem przełączyć $ ('*') na $ (': not ("# dialog, # dialog *") '), nadal wykrywał # kliknięć dialogów.

W każdym razie używałem tego wyłącznie do foto lightboxa, więc działało dobrze w tym celu.

Volomike
źródło
2

Podany przykład (y) używa jednego okna dialogowego o identyfikatorze '#dialog', potrzebowałem rozwiązania, które zamknie każde okno dialogowe:

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

Dziękuję mojemu koledze Youri Arkesteijn za sugestię użycia prototypu.

David van der Tuijn
źródło
2

To jedyna metoda, która zadziałała w moim przypadku w przypadku mojego NIEMODALNEGO okna dialogowego

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

Cały zasługa należy przypisać Axle
Click poza dialogiem niemodalnym, aby zamknąć

Colin
źródło
1

Korzystam z tego rozwiązania na podstawie jednego zamieszczonego tutaj:

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
źródło
1

Miałem ten sam problem podczas tworzenia podglądu modalnego na jednej stronie. Po wielu googlach znalazłem to bardzo przydatne rozwiązanie. W przypadku zdarzenia i celu sprawdza, gdzie nastąpiło kliknięcie iw zależności od tego, czy wyzwala akcję, czy nic nie robi.

Witryna biblioteki fragmentów kodu

$('#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
źródło
0

To proste, w rzeczywistości nie potrzebujesz żadnych wtyczek, po prostu jquery lub możesz to zrobić za pomocą prostego javascript.

$('#dialog').on('click', function(e){
  e.stopPropagation();
});
$(document.body).on('click', function(e){
  master.hide();
});
Rzasgal
źródło
0

Nie sądzę, aby znajdowanie elementów dialogowych za pomocą $ ('. Any-selector') z całego DOM było takie jasne.

Próbować

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

Naprawdę otrzymujesz nakładkę z instancji okna dialogowego, do którego należy, nic nie pójdzie źle w ten sposób.

zły chłopiec
źródło
To jest dla modalnego okna dialogowego? Mój OP jest niemodalny, więc nie ma nakładki.
Sonny
0

Za pomocą poniższego kodu możesz zasymulować kliknięcie przycisku „zamknij” w oknie dialogowym (zmień ciąg „MY_DIALOG” na nazwę własnego okna dialogowego)

$("div[aria-labelledby='ui-dialog-title-MY_DIALOG'] div.ui-helper-clearfix a.ui-dialog-titlebar-close")[0].click();
perkas
źródło
0

Inteligentny kod: używam następującego kodu, aby wszystko było jasne i czytelne. korpus zewnętrzny zamyka okno dialogowe.

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

function closeDialogBox() {
    $('#dialog-message').dialog('close');
}
Farid Abbas
źródło
0

Skończyło się na tym, że użyłem tego kodu, który powinien działać na wszystkich otwartych oknach dialogowych na stronie, ignorować kliknięcia etykietek narzędzi i czyścić zasoby zamykanego okna dialogowego.


        $(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
źródło