Reputation: 1927
I am trying to develop a bookmarklet. The purpose of the bookmarklet is to display the URL of both the current tab and the new tab that was launched as a result of a window.open
call. To simplify things, assume that the launcher.com
launches a random URL to visit.
function getBothURLs() {
var currentURL, newWin;
function launchNew () {
currentURL = window.location.href;
newWin = window.open("https://www.launcher.com");
}
launchNew();
alert(currentURL);
alert(newWin.location.href); // displays 'about:blank'
}
I am unable to get the URL of the newly launched tab. The alert()
(at the very end of the function below) does not correctly display the newly launch tab's URL; instead it displays
about:blank
When I was troubleshooting this within the Chrome console, I moved the definition of var currentURL, newWin
to outside the scope of the getTwoURLs()
function. When I invoked the function getBothURLs()
from within the console, both currentURL
and newWin
had valid data.
How should the function getBothURLs()
be modified to achieve the desired purpose?
Upvotes: 1
Views: 654
Reputation: 9102
A note on window.open from MDN:
...remote URLs won't load immediately. When window.open() returns, the window always contains about:blank. The actual fetching of the URL is deferred and starts after the current script block finishes executing...
In the above case the current blocks ends with the getBothURLs()
function, but you attempt to check the new URL within that block itself, and according to the quote above, you see the about:blank
url.
To fix this just defer the lookup until the next task. You can use something like setTimeout
to post the lookup onto the next task or, even better, use Promises if you wish to return the value from the function.
A sample implementation could look like:
function getBothURLs() {
return new Promise((resolve) => {
var newWin = window.open("//www.stackoverflow.com");
setTimeout(() => resolve(newWin))
}).then((win) => {
return new Promise((resolve, reject) => {
var check = setInterval(() => {
try {
if(win.location.href !== "about:blank"){
clearInterval(check);
resolve(win.location.href)
}
} catch(e) {
clearInterval(check);
reject(e);
}
}, 50)
})
})
}
getBothURLs().then(url => console.log(url))
Although, the above mentioned solution works, I would still recommend that you store new window's URL in a variable and then call open
with that variable.
This example snippet uses the non-promise callback version that could return both the urls. Although, it's possible to modify the promise version to return two urls as well but since the OP asked for a non-promise based version in the comments so I provided the new snippet. Have a look:
function getBothURLs(callback){
var current = window.location.href;
var win = window.open("https://stackoverflow.com");
var check = setInterval(() => {
try {
if(win.location.href !== "about:blank"){
clearInterval(check);
callback(null, current, win.location.href)
}
} catch(e) {
clearInterval(check);
callback(e);
}
}, 50);
}
getBothURLs((err, _cur, _new) => {
if(err){
// some error occurred, probably a cross-origin access
console.error("Failed to get URL", err);
return;
}
console.log(`Current: ${_cur} New: ${_new}`);
})
Upvotes: 1