Umgehen Sie den Popup-Blocker in window.open, wenn JQuery event.preventDefault () festgelegt ist

98

Ich möchte ein JQuery-Dialogfeld unter Vorbehalt des Klickereignisses eines Hyperlinks anzeigen.

Ich habe eine Anforderung wie unter Bedingung1: Öffnen Sie einen JQuery-Dialog. Wenn Bedingung1 nicht erfüllt ist, navigieren Sie zu der Seite, auf die durch das 'href'-Tag verwiesen wird, dessen Klickereignis in Frage kommt.

Ich kann eine Funktion für das Klickereignis des Links aufrufen. Diese Funktion überprüft nun diesen Zustand, indem sie eine andere URL ausführt (die meinen Spring-Controller ausführt und eine Antwort zurückgibt).

Alles funktioniert perfekt, wenn nur window.open vom Popup-Blocker blockiert wird.

$('a[href*=/viewpage?number]').live('click', function(e) {
    e.preventDefault();
    redirectionURL = this.href;
    pageId= getUrlVars(redirectionURL)["number"];
    $.getJSON("redirect/" + pageId, {}, function(status) {
        if (status == null) {
            alert("Error in verifying the status.");
        } else if(!status) {
            $("#agreement").dialog("open");
        } else {
            window.open(redirectionURL);
        }
    });
});

Wenn ich e.preventDefault();aus dem Code entferne , blockiert der Popoup-Blocker die Seite nicht, öffnet jedoch für Bedingung1 den Dialog sowie die Seite 'href'.

Wenn ich eines löse, entsteht ein Problem für ein anderes. Ich kann nicht beiden Bedingungen gleichzeitig gerecht werden.

Könnten Sie mir bitte helfen, dieses Problem zu lösen?

Sobald dies gelöst ist, muss ich ein weiteres Problem lösen, nämlich die Navigation im OK-Ereignis des Dialogs :)

Mavaze
quelle
1
versuche nicht .live zu verwenden, es ist veraltet und ein Zeiger auf .on ()!
Mas-Designs
@ EvilP: Wie andere dir letztes Mal gesagt haben, nur ab Version 1.7. Eine Menge von Projekten wird immer noch auf 1,5 oder 1,6 sein.
TJ Crowder
10
Downvoter: Nur weil Sie Popups nicht mögen, heißt das nicht, dass diese Frage abgelehnt werden sollte. Eine Frage sollte abgelehnt werden, wenn sie "... keinen Forschungsaufwand zeigt; wenn sie unklar oder nicht nützlich ist" . Die Frage ist klar, scheint nicht faul zu sein und ergibt sich aus einer nicht trivialen Kombination von Faktoren.
TJ Crowder
@TJCrowder: Er hat nicht angegeben, welche Version er verwendet. Daher sollte ich berücksichtigen, dass er die neueste Version verwendet. Wenn er eine andere Version verwendet, würde er dies sicher erwähnen, da er sich dann der Tatsache bewusst sein würde, dass Live veraltet ist, und erklären würde, WARUM er .live () verwendet. Niemand hat mir jemals das "letzte" Mal gesagt, also solltest du dir eine Pause gönnen und dich beruhigen. Es ist nicht nötig, so hart zu sein ...
mas-designs
Ich habe keine Benachrichtigung darüber erhalten. Aber ist es nicht normal zu bedenken, dass jemand, der seine Version nicht angibt, die neueste Version verwendet? Ich meine, ich muss 1.3 aus einem bestimmten Grund verwenden und bin mir der Tatsache bewusst, dass es eine neuere und bessere Version gibt.
Mas-Designs

Antworten:

144

Popup-Blocker sind normalerweise nur zulässig, window.openwenn sie während der Verarbeitung eines Benutzerereignisses verwendet werden (z. B. durch Klicken). In Ihrem Fall rufen Sie window.open später an , nicht während des Ereignisses, da $.getJSONes asynchron ist.

Sie haben zwei Möglichkeiten:

  1. Mach etwas anderes als window.open.

  2. Machen Sie den Ajax-Aufruf synchron, was Sie normalerweise vermeiden sollten, wie die Pest, da sie die Benutzeroberfläche des Browsers blockiert. $.getJSONist äquivalent zu:

    $.ajax({
      url: url,
      dataType: 'json',
      data: data,
      success: callback
    });

    ... und so können Sie Ihren $.getJSONAnruf synchronisieren, indem Sie Ihre Parameter den oben genannten zuordnen und Folgendes hinzufügen async: false:

    $.ajax({
        url:      "redirect/" + pageId,
        async:    false,
        dataType: "json",
        data:     {},
        success:  function(status) {
            if (status == null) {
                alert("Error in verifying the status.");
            } else if(!status) {
                $("#agreement").dialog("open");
            } else {
                window.open(redirectionURL);
            }
        }
    });

    Auch hier befürworte ich keine synchronen Ajax-Anrufe, wenn Sie einen anderen Weg finden, um Ihr Ziel zu erreichen. Aber wenn du nicht kannst, los geht's.

    Hier ist ein Beispiel für Code, der den Test aufgrund des asynchronen Aufrufs nicht besteht:

    Live Beispiel | Live-Quelle (Die Live-Links funktionieren aufgrund von Änderungen an JSBin nicht mehr.)

    jQuery(function($) {
      // This version doesn't work, because the window.open is
      // not during the event processing
      $("#theButton").click(function(e) {
        e.preventDefault();
        $.getJSON("http://jsbin.com/uriyip", function() {
          window.open("http://jsbin.com/ubiqev");
        });
      });
    });

    Und hier ist ein Beispiel, das mit einem synchronen Aufruf funktioniert:

    Live Beispiel | Live-Quelle (Die Live-Links funktionieren aufgrund von Änderungen an JSBin nicht mehr.)

    jQuery(function($) {
      // This version does work, because the window.open is
      // during the event processing. But it uses a synchronous
      // ajax call, locking up the browser UI while the call is
      // in progress.
      $("#theButton").click(function(e) {
        e.preventDefault();
        $.ajax({
          url:      "http://jsbin.com/uriyip",
          async:    false,
          dataType: "json",
          success:  function() {
            window.open("http://jsbin.com/ubiqev");
          }
        });
      });
    });
TJ Crowder
quelle
3
Tausend Dank. Ihr Vorschlag, einen Anruf synchron zu machen, wirkte wie ein Zauber. Das Gleiche hat mir in meiner wahrscheinlich nächsten Ausgabe zum Umgang mit der Navigation beim OK-Ereignis des Dialogs geholfen.
Mavaze
Da TJ Crowder 2 Fragen offen gelassen hat, [1. Alternative zu window.open finden] und [2. Vermeiden Sie Ajax-Synchronanrufe] Vorschläge zu diesen sind zum Nutzen der Community willkommen.
Sonst
4
Für mich habe ich einen Link mit target = "_ blank" hinzugefügt, um den Benutzer zum Klicken aufzufordern.
Hiroshi
1
@Evan: Sie müssen XHR direkt verwenden. Das Ticket enthält ein Beispiel für die Ablehnung synchroner Anforderungen .
TJ Crowder
2
@mavaze Ich denke, Sie können beide Probleme vermeiden, wenn Sie den Kontrollfluss so ändern können, dass zuerst das Fenster geöffnet (synchronisiert), dann die AJax-Anforderung (asynchron) ausgeführt und dann die Antwort verwendet wird, um entweder die Fehlermeldung anzuzeigen oder die Umleitung durchzuführen.
Stijn de Witt
61

Sie können window.open ohne Browserblockierung nur aufrufen, wenn der Benutzer direkt eine Aktion ausführt. Der Browser sendet ein Flag und bestimmt das durch Benutzeraktion geöffnete Fenster.

Sie können dieses Szenario also ausprobieren:

  1. var myWindow = window.open ('')
  2. Zeichnen Sie eine Lademeldung in dieses Fenster
  3. Wenn die Anfrage fertig ist, rufen Sie einfach myWindow.location = ' http://google.com ' auf.
Evgeniy Kubyshin
quelle
2
Dies funktioniert nicht auf Safari Mobile (getestet auf IPhone 4). Ich habe verschiedene andere Ideen ausprobiert (z. B. myWindow.postMessage), aber aufgrund der Einschränkung von Safaris, JavaScript nicht im Hintergrund auszuführen, kann das übergeordnete Fenster diese Standortänderung niemals senden.
Roundrobin
@BausTheBig Ich habe auf IPhone 6, IOS8 getestet. Es funktionierte wie ein Zauber.
lvarayut
suchte nach einer Möglichkeit, externe Links mit Google Analytics zu verfolgen, ohne dass Popups blockiert werden. Das war genau das, was ich brauchte. Scheint auf dem iPhone 4s in iOS7 (aktuelles Telefon) und iOS 8 (iOS Simulator) gut zu funktionieren.
Notacouch
37

Ich hatte dieses Problem und hatte meine URL nicht bereit, bis der Rückruf einige Daten zurückgab. Die Lösung bestand darin, vor dem Starten des Rückrufs ein leeres Fenster zu öffnen und dann den Ort festzulegen, an dem der Rückruf zurückkehrt.

$scope.testCode = function () {
    var newWin = $window.open('', '_blank');
    service.testCode().then(function (data) {
        $scope.testing = true;
        newWin.location = '/Tests/' + data.url.replace(/["]/g, "");
    });
};
KnuturO
quelle
1
Ich habe diese Lösung verwendet, um ein neues Fenster zu öffnen und den Popupblocker zu umgehen
VeldMuijz
Was ist, wenn ich vorher nicht weiß, ob ich das Popup öffnen muss? Wie in: action().then(doWindowOpenThing).catch(doSomethingElseThatDoesntOpenAPopup) Also kann ich ein Fenster nicht vorher öffnen (um seine Referenz zu behalten usw.), wenn ich es später nicht mehr benutze, oder?
Luiz
Nein, es würde jedes Mal einen neuen Tab öffnen und ich denke, Sie würden das nicht wollen, wenn Sie es nicht verwenden. Der Browser erlaubt Ihnen nur, eine neue Registerkarte in der Klickfunktion zu öffnen (vom Benutzer initiierte Aktion), andernfalls sieht der Popup-Blocker dies als ein Skript, das eine neue Registerkarte ohne Benutzerberechtigung öffnet und blockiert.
KnuturO
Bitte testen Sie, ob newWin null ist!
FrancescoMM
Warum ? Ich sehe keinen Grund dafür.
KnuturO
18

versuchen Sie dies, es funktioniert für mich,

$('#myButton').click(function () {
    var redirectWindow = window.open('http://google.com', '_blank');
    $.ajax({
        type: 'POST',
        url: '/echo/json/',
        success: function (data) {
            redirectWindow.location;
        }
    });
});

Ist Geige für diese http://jsfiddle.net/safeeronline/70kdacL4/1/

Mohammed Safeer
quelle
1
Danke, hat auch für mich gearbeitet - ohne diese Geige hätte ich es wahrscheinlich nicht geglaubt, lol!
rmcsharry
3
Dies sollte die akzeptierte Antwort sein! Sie können auch redirectWindow.location.assign ('new_url') verwenden, wenn Sie zum Erstellen der URL asynchrone Daten benötigen.
Matheusr
Schöne Lösung.
Halten Sie
Bitte testen Sie, ob redirectWindow null ist! Je nach Browseroption können Sie blockiert werden oder nicht.
FrancescoMM
8

Windows muss auf demselben Stapel (auch als Mikrotask bezeichnet ) wie das vom Benutzer initiierte Ereignis erstellt werden, z. B. ein Klick-Rückruf. Sie können daher später nicht asynchron erstellt werden.

Sie können jedoch ein Fenster ohne URL erstellen und die URL dieses Fensters ändern, sobald Sie sie kennen , auch asynchron!

window.onclick = () => {
  // You MUST create the window on the same event
  // tick/stack as the user-initiated event (e.g. click callback)
  const googleWindow = window.open();

  // Do your async work
  fakeAjax(response => {
    // Change the URL of the window you created once you
    // know what the full URL is!
    googleWindow.location.replace(`https://google.com?q=${response}`);
  });
};

function fakeAjax(callback) {
  setTimeout(() => {
    callback('example');
  }, 1000);
}

Moderne Browser öffnen das Fenster mit einer leeren Seite (oft aufgerufen about:blank). Wenn Ihre asynchrone Aufgabe zum Abrufen der URL ziemlich schnell ist, ist die resultierende UX meistens in Ordnung. Wenn Sie stattdessen eine Lademeldung (oder etwas anderes) in das Fenster rendern möchten, während der Benutzer wartet, können Sie Daten-URIs verwenden .

window.open('data:text/html,<h1>Loading...<%2Fh1>');
Jayphelps
quelle
3

Dieser Code hilft mir. Hoffe das hilft einigen Leuten

$('formSelector').submit( function( event ) {

    event.preventDefault();

    var newWindow = window.open('', '_blank', 'width=750,height=500');

    $.ajax({

        url: ajaxurl,
        type: "POST",
        data: { data },

    }).done( function( response ) {

        if ( ! response ) newWindow.close();
        else newWindow.location = '/url';

    });
});
Richard
quelle
3

Versuchen Sie, eine mit einem Link - Elemente und klicken Sie mit javascriipt

<a id="SimulateOpenLink" href="#" target="_blank" rel="noopener noreferrer"></a>

und das Skript

function openURL(url) {
    document.getElementById("SimulateOpenLink").href = url
    document.getElementById("SimulateOpenLink").click()
}

Verwenden Sie es so

//do stuff
var id = 123123141;
openURL("/api/user/" + id + "/print") //this open webpage bypassing pop-up blocker
openURL("https://www.google.com") //Another link
Fernando Carvajal
quelle
Dadurch wurde es für mich vermieden, mit dem leeren Fenster umzugehen.
ponder275
Es stellte sich heraus, dass dies mein Problem mit dem iPhone, das mein Fenster als Popup blockierte, nicht löste.
ponder275
2

Die Beobachtung, dass das Ereignis vom Benutzer initiiert werden musste, half mir, den ersten Teil davon herauszufinden, aber auch danach blockierten Chrome und Firefox das neue Fenster. Der zweite Teil war das Hinzufügen von target = "_ blank" zu dem Link, der in einem Kommentar erwähnt wurde.

Zusammenfassend: Sie müssen window.open von einem vom Benutzer initiierten Ereignis aus aufrufen, in diesem Fall auf einen Link klicken, und dieser Link muss target = "_ blank" haben.

Im folgenden Beispiel verwendet der Link class = "button-twitter".

$('.button-twitter').click(function(e) {
  e.preventDefault();
  var href = $(this).attr('href');
  var tweet_popup = window.open(href, 'tweet_popup', 'width=500,height=300');
});
Alexis Bellido
quelle
2
var url = window.open("", "_blank");
url.location = "url";

das hat bei mir funktioniert.

Diego Santa Cruz Mendezú
quelle
1

Ich verwende diese Methode, um den Popup-Blocker in meinem Reaktionscode zu vermeiden. Es funktioniert auch in allen anderen Javascript-Codes.

Wenn Sie beim Klicken einen asynchronen Aufruf tätigen, öffnen Sie zuerst ein leeres Fenster und schreiben Sie die URL später ein, wenn ein asynchroner Aufruf abgeschlossen ist.

const popupWindow = window.open("", "_blank");
popupWindow.document.write("<div>Loading, Plesae wait...</div>")

Schreiben Sie nach dem Erfolg eines asynchronen Aufrufs Folgendes

popupWindow.document.write(resonse.url)
Tabish
quelle