18

I have a situation where, when a user pushes a button I perform an ajax request, and then use the result of the ajax request to generate a URL which I want to open in a new tab. However, in chrome when I call window.open in the success handler for the ajax request, it opens in a new window like a popup (and is blocked by popup-blockers). My guess is that since the the success code is asynchronous from the click handling code that chrome thinks it wasn't triggered by a click, even though it is causally related to a click. Is there any way to prevent this without making the ajax request synchronous?

EDIT Here is some minimal code that demonstrates this behaviour:

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

http://jsfiddle.net/ESMUA/2/

One note of clarification: I am more conerned about it opening in a separate window rather than a tab, than I am about it being blocked by a popup blocker.

Thayne
  • 6,619
  • 2
  • 42
  • 67

5 Answers5

22

Try to add

window.open(url,'_blank');

Edit

Well, I don't think you can get around popup-blockers when opening a page that's not the immediate result of a user action (i.e. not async).

You could try something like this though, it should look like a user action to a popup-blocker:

var $a = $('<a>', {
        href: url,
        target: '_blank' 
    });

$(document.body).append($a);
$a.click();

Edit 2

Looks like you're better of keeping things sync.

As long as the new window is "same origin" you have some power to manipulate it with JS.

$('#a').on('click', function(e){
    e.preventDefault();
    var wi = window.open('about:blank', '_blank');

    setTimeout(function(){ // async
        wi.location.href = 'http://google.com';
    }, 500);
});
pstenstrm
  • 6,339
  • 5
  • 41
  • 62
  • that is what I am using – Thayne Feb 25 '14 at 07:55
  • Edited my answer with a different solution. Sorry for assuming jQuery – pstenstrm Feb 25 '14 at 08:04
  • unfortunately, the click event doesn't actually trigger the link (although javascript event handlers are called). This is probably disallowed for security reasons. – Thayne Feb 25 '14 at 08:25
  • 1
    Yes, see http://stackoverflow.com/questions/2587677/avoid-browser-pop-up-blockers – Asons Feb 25 '14 at 08:25
  • 2
    Edit 2 works, although it may may not be a great experience for the user if the ajax request takes a long time to respond, it should work fine for my purposes though. – Thayne Feb 25 '14 at 18:21
  • Edit 2 worked for me. I still prefer the user staring a white window instead of locked browser due to sync ajax call.. – KnF May 06 '15 at 21:29
14

Try adding async: false. It should be working

$('#myButton').click(function() {
$.ajax({
    type: 'POST',
    async: false,
    url: '/echo/json/',
    data: {'json': JSON.stringify({
        url:'http://google.com'})},
    success: function(data) {
        window.open(data.url,'_blank');
    }
});
});
rajesh
  • 382
  • 4
  • 5
  • 2
    Yeah this makes chrome treat it like a user action, well done! – njfife Jul 23 '14 at 23:58
  • 3
    Yes, but it locks the browser until the request is finished. Thats the dark side of sync requests... I use those in very extreme situations. – KnF May 06 '15 at 21:26
12

What worked for me was:

var win = window.open('about:blank', '_blank');

myrepository.postmethod('myserviceurl', myArgs)
.then(function(result) {
    win.location.href = 'http://yourtargetlocation.com/dir/page';
});

You open the new window tab before the sync call while you're still in scope, grab the window handle, and then re-navigate once you receive the ajax results in the promise.

bughunter1999
  • 194
  • 2
  • 4
9

The answer posted by @pstenstrm above (Edit 2) mostly works, but I added just one line to it to make the solution more elegant. The ajax call in my case was taking more than a second and the user facing a blank page posed a problem. The good thing is that there is a way to put HTML content in the new window that we've just created.

e.g:

$('#a').on('click', function(e){
    e.preventDefault();
    var wi = window.open('about:blank', '_blank');
    $(wi.document.body).html("<p>Please wait while you are being redirected...</p>");

    setTimeout(function(){ // async
        wi.location.href = 'http://google.com';
    }, 500);
});

This fills the new tab with the text "Please wait while you are being redirected..." which seems more elegant than the user looking at a blank page for a second. I wanted to post this as the comment but don't have enough reputation.

Afzal Naushahi
  • 175
  • 1
  • 4
  • Clever, but it doesn't seem to work in the latest Firefox. Solution is probably to setup a static "You are being redirected" page since about:blank is apparently not mutable. – Jordan Rieger Jan 03 '18 at 21:02
1

There is no reliable way. If your tab/window has been blocked by a pop-blocker in FF and IE6 SP2 then window.open will return the value null.

https://developer.mozilla.org/en-US/docs/Web/API/Window/open#FAQ

How can I tell when my window was blocked by a popup blocker? With the built-in popup blockers of Mozilla/Firefox and Internet Explorer 6 SP2, you have to check the return value of window.open(): it will be null if the window wasn't allowed to open. However, for most other popup blockers, there is no reliable way.

Ilker Cat
  • 1,862
  • 23
  • 17