We ran across this same problem and hunted around SO for an answer. What we found works in our circumstances and the distilled wisdom is as follows:
The problem is related to browser pop-up blockers preventing programmatic window opens. Browsers allow window opens from actual user clicks which occur on the main thread. Similarly, if you call window.open on the main thread it will work, as noted above. According to this answer on Open a URL in a new tab (and not a new window) using JavaScript if you are using an Ajax call and want to open the window on success you need to set async: false which works because that will keep everything on the main thread.
We couldn't control our Ajax call like that, but found another solution that works because of the same reasons. Warning, it is a bit hacky and may not be appropriate for you given your constraints. Courtesy of a comment on a different answer on Open a URL in a new tab (and not a new window) using JavaScript you open the window before calling setTimeout and then update it in the delayed function. There are a couple of ways of doing this. Either keep a reference to the window when you open it, w = window.open... and set w.location or open with a target, window.open('', 'target_name'), in the delayed function open in that target, window.open('your-url', 'target_name'), and rely on the browser keeping the reference.
Of course, if the user has their settings to open links in a new window this isn't going to change that, but that wasn't a problem for the OP.
Answer from Yogh on Stack OverflowWe ran across this same problem and hunted around SO for an answer. What we found works in our circumstances and the distilled wisdom is as follows:
The problem is related to browser pop-up blockers preventing programmatic window opens. Browsers allow window opens from actual user clicks which occur on the main thread. Similarly, if you call window.open on the main thread it will work, as noted above. According to this answer on Open a URL in a new tab (and not a new window) using JavaScript if you are using an Ajax call and want to open the window on success you need to set async: false which works because that will keep everything on the main thread.
We couldn't control our Ajax call like that, but found another solution that works because of the same reasons. Warning, it is a bit hacky and may not be appropriate for you given your constraints. Courtesy of a comment on a different answer on Open a URL in a new tab (and not a new window) using JavaScript you open the window before calling setTimeout and then update it in the delayed function. There are a couple of ways of doing this. Either keep a reference to the window when you open it, w = window.open... and set w.location or open with a target, window.open('', 'target_name'), in the delayed function open in that target, window.open('your-url', 'target_name'), and rely on the browser keeping the reference.
Of course, if the user has their settings to open links in a new window this isn't going to change that, but that wasn't a problem for the OP.
Like the other posts mentions the best way to do this is to first open the window and then set its location after the callback or asynchronous function
<input type="button" value="Open" onclick="cb1()">
<script type="text/javascript">
function cb1() {
var w = window.open('', 'w2');
setTimeout(function () {
wo(w);
}, 1000); //simple async
}
function wo(w)
{
w.location = "http://google.com";
w.focus();
}
</script>
Alternatively if you are using async await you will also have the same problem. The same solution still applies.
public async openWindow(): Promise<void> {
const w = window.open('', '_blank');
const url = await getUrlAsync();
w.location = url;
}
A further enhancement is to open the window on an initial page that provides some quick feedback either by loading a url or writing some html to that page
public async openWindow(): Promise<void> {
const w = window.open('', '_blank');
w.document.write("<html><head></head><body>Please wait while we redirect you</body></html>");
w.document.close();
const url = await getUrlAsync();
w.location = url;
}
This will prevent a user looking at a blank tab/window for however long it takes to resolve your URL.
Updated for comments: If you're opening your window via window.open() then in your child page you can set a function in the child to just be a reference pointing to a parent function, so have this in the child page:
var RunCallbackFunction = function() { }; //reference holder only
Then in your parent (opener), set that function when that child window loads, like this:
//random function you want to call
function myFunc() { alert("I'm a function in the parent window"); }
//to actually open the window..
var win = window.open("window.html");
win.onload = function() { win.RunCallbackFunction = myFunc; };
This assigns the function in your parent to now be the target of that child...and you can point each child to a different function if you wish, they're all independent.
sorry to up an old question but I needed to do something similar and felt the need to share a solution I'm happy with.
Parent:
window.open('CHILD_URL', 'CHILD_NAME');
window.addEventListener('message', (event) => {
if (event.origin !== 'CHILD_URL') return;
console.log(event.data);
});
Child:
window.opener.postMessage(data, document.referrer);
window.close();
Source (with some security warnings and detailed doc): https://developer.mozilla.org/docs/Web/API/Window/open
Javascript Window opener and callback
Window.open callback returns undefined for new window
Return a value from window.open - javascript
javascript - Callback function call when child window is close
You may call a parent function from child window this way:
window.opener.your_function()
To call a child function in parent window:
var w = window.open(somelocation,''); //has a function on `window` called "test"
w.test();
If any of this tips help you, you may show us how the callback approach was used by you.
Hope this helps you.
Regards!
In the example you gave us the function is called on load event, so you have to change it with on close event:
// This function is defined in the child window
var RunCallbackFunction = function() { }; //reference holder only
// ---------------------------------------------------------------------------
// This code should appear in the parent window
//random function you want to call
function myFunc() { alert("I'm a function in the parent window"); }
//to actually open the window..
var win = window.open("window.html");
win.onclose = function() { win.RunCallbackFunction = myFunc; };
HTML5's postMessage comes to mind. It's designed to do exactly what you're trying to accomplish: post messages from one window and process it in another.
https://developer.mozilla.org/en/DOM/window.postMessage
The caveat is that it's a relatively new standard, so older browsers may not support this functionality.
http://caniuse.com/#feat=x-doc-messaging
It's pretty simple to use:
To send a message from the source window:
window.postMessage("message", "*");
//'*' is the target origin, and should be specified for security
To listen for messages in a target window:
window.addEventListener
("message", function(e) {
console.log(e.data); //e.data is the string message that was sent.
}, true);
After few more hours of experiments, I think, I've found a viable solution for my problem.
The point is to reference jQuery from parent window and trigger a jQuery event on this window (I'm a Mac user but I suppose, jQuery has events working cross-platform, so IE compatibility is not an issue here).
This is my code for click handler on anchor...
$(this).find('a[x-special="select-asset"]').click(function() {
var evt = jQuery.Event('assetSelect', {
url: 'this is url',
closePopup: true,
});
var _parent = window.opener;
_parent.jQuery(_parent.document).trigger(evt);
});
... and this is the code of event handler:
$(document).bind('assetSelect', function (evt) {
console.log(evt);
});
This solution is fine, if you don't need to distinguish between multiple instances of the asset selection windows (only one window will dispatch "assetSelect" event). I have not found a way to pass a kind of tag parameter to window and then pass it back in event.
Because of this, I've chosen to go along with (at the end, better and visually more pleasant) solution, Fancybox. Unfortunately, there is no way - by default - to distinguish between instances either. Therefore, I've extended Fancybox as I've described in my blog post. I'm not including the full text of blog post here, because is not the topic of this question.
URL of the blog post: http://82517.tumblr.com/post/23798369533/using-fancybox-with-iframe-as-modal-dialog-on-a-web
Using below code you can navigate form lightning.
var urlEvent = $A.get("e.force:navigateToURL");
urlEvent.setParams({
"url": someurl
});
urlEvent.fire();
I just wanted to add a possible reason why this window.open failed in the first place.
Browsers are increasingly designed to prevent unwanted pop-up windows. As a result, if you try and open a brand new window that is not in direct response to an interaction (click, keystroke etc) by the user, the built-in pop-up blocker usually stops it.
Because you are doing asynchronous work between the user's interaction and the window.open, the browser no longer considers it to be in direct response to user interaction and blocks the pop-up. So one alternative, as you have noted, is a same-window redirect. Another alternative is a flow that opens the window immediately in response to an interaction and then does the processing. For example you could open a Visualforce page in the new window that runs your decision logic in the Apex controller and then either does a redirect or closes itself.
While the accepted answer is correct for same origins I found a solution for cross origin popups:
var win = window.open('http://www.google.com');
var timer = setInterval(function() {
if(win.closed) {
clearInterval(timer);
alert('closed');
}
}, 1000);
Source: atashbahar.com
For those considering using it.
Even Facebook is using this "hack" in their Javascript SDK.
You can verify this by having a look at their code. Just search for .closed in https://connect.facebook.net/en_US/sdk.js.
Your example will work as long as the pop-up window url is in the same domain as the parent page, and you change the event to all lowercase:
var new_window = window.open('some url')
new_window.onbeforeunload = function(){ /* my code */ }