Ignora il blocco dei popup su window.open quando è impostato JQuery event.preventDefault ()


98

Voglio mostrare una finestra di dialogo JQuery in modo condizionale sull'evento clic di un collegamento ipertestuale.

Ho un requisito come a condizione1 aprire una finestra di dialogo JQuery e se la condizione1 non è soddisfatta, vai alla pagina a cui fa riferimento il tag "href" del cui evento clic è in questione.

Sono in grado di chiamare una funzione sull'evento clic del collegamento. Questa funzione ora controlla la suddetta condizione eseguendo un altro URL (che esegue il mio controller Spring e restituisce la risposta).

Tutto funziona perfettamente con solo window.open bloccato dal blocco popup.

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

Se rimuovo e.preventDefault();dal codice, il blocco popoup non blocca la pagina, tuttavia per condition1 apre la finestra di dialogo e la pagina "href".

Se ne risolvo uno, crea problemi per un altro. Non sono in grado di rendere giustizia a entrambe le condizioni contemporaneamente.

Puoi aiutarmi a risolvere questo problema per favore?

Una volta risolto, ho un altro problema da risolvere, ad esempio la navigazione sull'evento OK del dialogo :)


1
cerca di non usare .live è deprecato e un puntatore a .on ()!
mas-designs

@EvilP: Come altri ti hanno detto l'ultima volta, solo nella versione 1.7 e successive. Un sacco di progetti sarà ancora il 1.5 o 1.6.
TJ Crowder

10
Downvoter: solo perché non ti piacciono i popup, ciò non significa che questa domanda debba essere sottovalutata. Una domanda dovrebbe essere sottovalutata se "... non mostra alcuno sforzo di ricerca; se non è chiaro o non è utile" . La domanda è chiara, non sembra pigra e nasce da una combinazione di fattori non banale.
TJ Crowder

@TJCrowder: non ha specificato quale versione sta utilizzando. Quindi dovrei considerare che sta usando l'ultima versione. Se sta usando una versione diversa, sono sicuro che lo menzionerebbe perché ALLORA sarebbe consapevole del fatto che live è deprecato e spiegherebbe PERCHE 'sta usando .live (). Nessuno mi ha mai detto l '"ultima" volta quindi penso che dovresti prenderti una pausa e calmarti. Non c'è bisogno di essere così duri ...
mas-designs

Non ho ricevuto alcuna notifica in merito. Ma non è normale considerare che se qualcuno non specifica la propria versione considerare che sta utilizzando l'ultima? Voglio dire, devo usare 1.3 per un motivo e sono consapevole del fatto che esiste una versione più recente e migliore.
mas-designs

Risposte:


144

I blocchi popup in genere consentono solo window.opense utilizzati durante l'elaborazione di un evento utente (come un clic). Nel tuo caso, chiami window.open più tardi , non durante l'evento, perché $.getJSONè asincrono.

Hai due opzioni:

  1. Fai qualcos'altro, piuttosto che window.open.

  2. Rendi sincrona la chiamata ajax, che è qualcosa che normalmente dovresti evitare come la peste in quanto blocca l'interfaccia utente del browser. $.getJSONè equivalente a:

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

    ... e così puoi rendere la tua $.getJSONchiamata sincrona mappando i tuoi parametri a quanto sopra e aggiungendo 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);
            }
        }
    });

    Ancora una volta, non sostengo le chiamate ajax sincrone se riesci a trovare un altro modo per raggiungere il tuo obiettivo. Ma se non puoi, eccoti.

    Ecco un esempio di codice che non supera il test a causa della chiamata asincrona:

    Esempio dal vivo | Sorgente live (i collegamenti live non funzionano più a causa delle modifiche a JSBin)

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

    Ed ecco un esempio che funziona, utilizzando una chiamata sincrona:

    Esempio dal vivo | Sorgente live (i collegamenti live non funzionano più a causa delle modifiche a JSBin)

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

3
Grazie mille. Il tuo suggerimento di rendere la chiamata sincrona ha funzionato a meraviglia. Lo stesso mi ha aiutato nel mio probabile prossimo numero di gestire la navigazione sull'evento OK del dialogo.
mavaze

Poiché TJ Crowder ha lasciato 2 domande aperte, [1. trova alternativa a window.open] e [2. evitare la chiamata sincrona ajax] suggerimenti su quelli sono benvenuti a beneficio della comunità. Altrimenti ho trovato la sua risposta una soluzione perfetta per la suddetta domanda :)
mavaze

4
Per me, ho aggiunto un collegamento con target = "_ blank" per richiedere all'utente di fare clic.
Hiroshi

1
@Evan: dovrai usare XHR direttamente. C'è un esempio nel ticket per deprecare le richieste sincrone .
TJ Crowder

2
@mavaze Penso che tu possa evitare entrambi i problemi se puoi modificare il flusso di controllo per aprire prima la finestra, (sincronizzazione), quindi eseguire la richiesta AJax (asincrona) e quindi utilizzare la risposta per mostrare il messaggio di errore o eseguire il reindirizzamento.
Stijn de Witt

61

puoi chiamare window.open senza bloccare il browser solo se l'utente fa direttamente qualche azione. Il browser invia alcuni flag e determina la finestra aperta dall'azione dell'utente.

Quindi, puoi provare questo scenario:

  1. var myWindow = window.open ('')
  2. disegnare qualsiasi messaggio di caricamento in questa finestra
  3. una volta completata la richiesta, chiama semplicemente myWindow.location = " http://google.com "

2
Questo non funziona su Safari Mobile (testato su IPhone 4). Ho provato molte altre idee (ad esempio myWindow.postMessage) ma a causa della restrizione di Safari di non eseguire JavaScript in background, la finestra principale non può mai inviare la modifica della posizione.
roundrobin

@BausTheBig ho provato su IPhone 6, IOS8. Ha funzionato come un fascino.
lvarayut

stava cercando un modo per monitorare i collegamenti esterni con Google Analytics senza che i popup venissero bloccati. Questo era esattamente ciò di cui avevo bisogno. Sembra funzionare bene su iPhone 4s in iOS7 (telefono effettivo) e iOS 8 (simulatore iOS).
notacouch

37

Ho avuto questo problema e non avevo il mio URL pronto fino a quando la richiamata non avrebbe restituito alcuni dati. La soluzione era aprire una finestra vuota prima di avviare la richiamata e quindi impostare semplicemente la posizione al ritorno della richiamata.

$scope.testCode = function () {
    var newWin = $window.open('', '_blank');
    service.testCode().then(function (data) {
        $scope.testing = true;
        newWin.location = '/Tests/' + data.url.replace(/["]/g, "");
    });
};

1
Ho usato questa soluzione per aprire una nuova finestra e bypassare il blocco popup
VeldMuijz

E se non sapessi in anticipo se avrò bisogno di aprire un popup? Come in: action().then(doWindowOpenThing).catch(doSomethingElseThatDoesntOpenAPopup) Quindi non posso aprire una finestra prima (per mantenere il suo riferimento, ecc.) Se in seguito non la userò, giusto?
Luiz

No, aprirà una nuova scheda ogni volta e immagino che non lo vorresti nel caso in cui non lo usi. Il fatto è che il browser ti consentirà solo di aprire una nuova scheda nella funzione clic (azione avviata dall'utente) altrimenti il ​​blocco popup lo vedrà come uno script che apre una nuova scheda senza l'autorizzazione dell'utente e lo bloccherà.
KnuturO

Per favore, prova se newWin è nullo!
FrancescoMM

Perché ? Non vedo motivo per questo.
KnuturO

18

prova questo, funziona per me,

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

È violino per questo http://jsfiddle.net/safeeronline/70kdacL4/1/


1
Grazie, ha funzionato anche per me - se non fosse stato per quel violino probabilmente non ci avrei creduto, lol!
rmcsharry

3
Questa dovrebbe essere la risposta accettata! Puoi anche utilizzare redirectWindow.location.assign ('new_url') se hai bisogno di dati asincroni per creare l'URL.
matheusr

Bella soluzione continua così
Shah NIral

Per favore, prova se redirectWindow è nullo! A seconda delle diverse opzioni del browser puoi essere bloccato o meno.
FrancescoMM

8

Windows deve essere creato sullo stesso stack (noto anche come microtask ) dell'evento avviato dall'utente, ad esempio un callback di clic, quindi non possono essere creati in seguito, in modo asincrono.

Tuttavia, puoi creare una finestra senza un URL e puoi quindi modificare l'URL di quella finestra una volta che lo conosci , anche in modo asincrono!

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

I browser moderni apriranno la finestra con una pagina vuota (spesso chiamata about:blank) e, supponendo che l'attività asincrona per ottenere l'URL sia abbastanza veloce, la UX risultante è per lo più soddisfacente. Se invece desideri eseguire il rendering di un messaggio di caricamento (o qualsiasi altra cosa) nella finestra mentre l'utente attende, puoi utilizzare gli URI dei dati .

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

3

Questo codice mi aiuta. Spero che questo aiuti alcune persone

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

    });
});

3

Prova a utilizzare un elemento di collegamento e fai clic su di esso con javascriipt

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

e il copione

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

Usalo in questo modo

//do stuff
var id = 123123141;
openURL("/api/user/" + id + "/print") //this open webpage bypassing pop-up blocker
openURL("https://www.google.com") //Another link

Questo mi ha evitato di occuparmi della finestra vuota.
ponder275

Si è scoperto che questo non ha risolto il mio problema con l'iPhone che bloccava la mia finestra come pop-up.
ponder275

2

L'osservazione che l'evento doveva essere avviato dall'utente mi ha aiutato a capire la prima parte di questo, ma anche dopo che Chrome e Firefox hanno bloccato ancora la nuova finestra. La seconda parte è stata l'aggiunta di target = "_ blank" al collegamento, che è stato menzionato in un commento.

In sintesi: è necessario chiamare window.open da un evento avviato dall'utente, in questo caso cliccando su un collegamento, e quel collegamento deve avere target = "_ blank".

Nell'esempio seguente il collegamento utilizza 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');
});


1

Sto usando questo metodo per evitare il blocco popup nel mio codice React. funzionerà anche con tutti gli altri codici javascript.

Quando si effettua una chiamata asincrona su un evento clic, è sufficiente aprire prima una finestra vuota e quindi scrivere l'URL in quella successiva quando una chiamata asincrona sarà completata.

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

in caso di esito positivo della chiamata asincrona, scrivere quanto segue

popupWindow.document.write(resonse.url)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.