Javascript,calling child window function from opener doesn't work - javascript

I'm developing a web application that opens a popup using windows.open(..). I need to call a function on the opened window using the handle returned by "window.open", but I'm always getting the error message "addWindow.getMaskElements is not a function", as if it couldn't access the function declared on child window. This is the behavior in both IE and FF. My code looks like this:
function AddEmail(target,category)
{
if(addWindow == null)
{
currentCategory = category;
var left = getDialogPos(400,220)[0];
var top = getDialogPos(400,220)[1];
addWindow = window.open("adicionar_email.htm",null,"height=220px, width=400px, status=no, resizable=no");
addWindow.moveTo(left,top);
addWindow.getMaskElements ();
}
}
I've googled and read from different reliable sources and apparently this is supposed to work, however it doesn't.
One more thing, the functions in child window are declared in a separate .js file that is included in the adicionar_email.htm file. Does this make a difference? It shouldn't..
So, if anyone has ran into a similar problem, or has any idea of what I'm doing wrong, please, reply to this message.
Thanks in advance.
Kenia

The window creation is not a blocking operation; the script continues to execute while that window is opening and loading the HTML & javascript and parsing it.
If you were to add a link on your original page like this:
Test
You'd see it works. (I tried it just to be sure.)
**EDIT **
Someone else posted a workaround by calling an onload in the target document, here's another approach:
function AddEmail()
{
if(addWindow == null) {
addWindow = window.open("test2.html",null,"height=220px, width=400px, status=no, resizable=no");
}
if(!addWindow.myRemoteFunction) {
setTimeout(AddEmail,1000);
} else { addWindow.myRemoteFunction(); }
}
This keeps trying to call addWindow.myRemoteFunction every 1 second til it manages to sucessfully call it.

The problem is that window.open returns fairly quickly, the document that is requested and then any other items that that document may subsequently refer to will not yet have been loaded into the window.
Hence attempting to call this method so early will fail. You should attach a function to the opened window's load event and attempt to make you calls from that function.

The problem with the below one is :
When the javascript is being executed in the parent window, the child window is not loading. Hence, the invoking function from parent window is in the infinite loop and it is leading to crashing the window.
The window creation is not a blocking operation; the script continues
to execute while that window is opening and loading the HTML &
javascript and parsing it.
If you were to add a link on your original page like this:
Test
You'd see it works. (I tried it just to be sure.)
**EDIT **
Someone else posted a workaround by calling an onload in the target
document, here's another approach:
function AddEmail()
{
if(addWindow == null) {
addWindow = window.open("test2.html",null,"height=220px, width=400px, status=no, resizable=no");
}
if(!addWindow.myRemoteFunction) {
setTimeout(AddEmail,1000);
} else { addWindow.myRemoteFunction(); }
}
This keeps trying to call addWindow.myRemoteFunction every 1 second
til it manages to sucessfully call it.

You are calling the function immediately after opening the window; the page on the popup may not be loaded yet, so the function may not be defined at that point.

Related

How can I run a script in another (newly-opened) tab?

I am trying to run a script in a new tab. The code I use is this:
$ = jQuery;
function openAndPush(url, id) {
var win = window.open('https://example.com' + url + '?view=map');
var element = $('<script type="text/javascript">console.log("Starting magic...");var region_id='+id+';$=jQuery;var p=$(\'div["se:map:paths"]\').attr(\'se:map:paths\');if(p){console.log("Found! pushing..."); $.get(\'https://localhost:9443/addPolygon\', {id: region_id, polygon: p}, function(){console.log("Done!")})}else{console.log("Not found!");}</script>').get(0);
setTimeout(function(){ win.document.body.appendChild(element);
console.log('New script appended!') }, 10000);
}
Considering the following:
I was inspired in this answer, but used jQuery instead.
I run this code in an inspector/console, from another page in https://example.com (yes, the actual domain is not example.com - but the target url is always in the same domain with respect to the original tab) to avoid CORS errors.
When I run the function (say, openAndPush('/target', 1)) and then inspect the code in another inspector, one for the new window, the console message Starting magic... is not shown (I wait the 10 seconds and perhaps more). However the new DOM element (this script I am creating) is shown in the Elements tab (and, in the first console/inspector, I can see the New script appended! message).
(In both cases jQuery is present, but not occupying the $ identifier, which seems to be undefined - so I manually occupy it)
What I conclude is that my script is not being executed in the new window.
What am I missing? How can I ensure the code is being executed?
Instead of embedding script element in the document, do this.
wrap the code that you want to run in another tab, into a function.
bind that wrapped function to the new tab's window
Call that function
Here's the code that I ran in my console and it worked for me i.e another tab was opened and alert was displayed.
function openAndPush(url, id) {
var win = window.open('https://www.google.com');
win.test = function () {
win.alert("Starting magic...");
}
win.test();
setTimeout(function () {
win.document.body.appendChild(element);
console.log('New script appended!')
}, 10000);
}
Found that my error consisted on the origin document being referenced when creating a new script node, instead of the target document (i.e. win.document). What I needed is to change the code to reference the new document and create the node directly, no jQuery in the middle at that point. So I changed my code like this:
function openAndPush(url, id) {
var win = window.open('https://streeteasy.com' + url + '?view=map');
var element = win.document.createElement('script');
element.type='text/javascript';
element.innerHTML = 'console.log("Starting magic...");var region_id='+id+';$=jQuery;var p=$(\'div[se\\\\:map\\\\:paths]\').attr(\'se:map:paths\');if(p){console.log("Found! pushing..."); $.get(\'https://localhost:9443/addPolygon\', {id: region_id, polygon: p}, function(){console.log("Done!")})}else{console.log("Not found! searched in: ", document);}'
setTimeout(function(){ win.document.body.appendChild(element); console.log('New script appended!') }, 10000);
}
With this code something is essentially happening: The JS code is being parsed (and its node created) in the context of the new document. Older alternatives involved the origin console (since the origin document was implicitly referenced).
It's bad practice to send scripts to another webpage. You can pass some query params using a complicated URL and handle it by a source code from another webpage, it's much better:
function doMagicAtUrlByRegionId (url, regionId) {
window.open(`https://example.com${url}?view=map&magic=true&region_id=${regionId}`);
}

Detecting when popup window is closed in Firefox

I open a new window like this:
var newWindow = window.open('myPage.aspx', null, 'height=650,width=900,status=yes,toolbar=no,scrollbars=yes,menubar=no,location=no,top=0, left=0');
And I wait for it to close:
var windowTimer = window.setInterval(function () {
if (win.closed !== false) {
//If window is closed ...
window.clearInterval(windowTimer);
}
}, 100);
This does work in Chrome and IE9 and Edge but not in Firefox, why?
Firefox does get inside the function but it never gets on win.closed if, even if there is an else it neither goes into it... is there any alternative to this?
Solution that worked for me:
On the popup window:
//Fires an event on the window that opened it
window.onbeforeunload = function () {
window.opener.myEvent();
};
On the main window:
window.myEvent= function () {
//This fires only when the popup gets closed on beforeunload
}
Note: the event to fire in the main window must be declared as public so it can be accessible, like so window.myEvent= function ()
Another reference: cross-window javascript events
Basically, I think the simplest way to do this is the following:
function hasClosed(){
document.getElementById('open').textContent = 'window has been closed';
}
window.addEventListener('beforeunload', function(){
if(window.opener) window.opener.hasClosed();
});
document.getElementById('open').addEventListener('click', function(e){
e.preventDefault();
window.open('test.html');
});
open window
Please keep in mind that SO snippets are not allowed to open windows, so the code is not functional inside the snippet. Simply copy the code and save it as a file called test.html.
You do not need to keep checking, the child will simply call the function on the parent. This has the advantage that you are not using resources to keep checking for it. Also, be aware that when navigating in this window, onbeforeunload gets called if a new page is loaded, calling the parent function, but maybe you could just do the check you were already doing in the hasClosed function.
You might want to give an uuid to your window and pass it into it so it can inform you of it's identity on closing, but that's all refinement.

Chrome Extension open popup relative to current window

I'm trying to create a Chrome extension that will pop up a new window in a position relative to the recently focused window. I don't think I'm using the chrome.windows.getCurrent or chrome.windows.getLastFocused methods properly to do this. Every time I do, I get an undefined alert when I try to show a property of that window.
In my background.js file, I have:
chrome.pageAction.onClicked.addListener(showPopup);
function showPopup() {
var left = chrome.windows.getCurrent(function (w) {
w.left - 200;
// also tried: return w.left - 200;
});
alert(left); // undefined
}
Reading the chrome.windows API docs left me confused on how to actually return an attribute of a window. Can anyone shed some light here?
I'm not sure if there's another (or better) way to do this, but I got this to work:
chrome.pageAction.onClicked.addListener(getCurrentInfo);
function getCurrentInfo() {
chrome.windows.getCurrent(showPopup);
}
function showPopup(win) {
alert(win.left); // correct pixel count from left
}
My original attempt was wrong because I was trying to return a value from the get() callback function and place that into a variable. This, essentially evaluated to var left = chrome.windows.get(winId, 790), which is an invalid function call. Rather than that, my call to chrome.windows.create() needed to be inside the callback function.
Also, a miss before was that the click listener calls a function with a tab parameter, not a window parameter. So I needed the getCurrentInfo() function to pass in a tab and then chrome.windows.getCurrent() to pass in window info.

Google Chrome Userscripts reference window.open

I have been trying to figure this one out for a while, but when I try to reference a window that I opened the handle is always undefined.
It is worth noting that this is being used in a userscript and here is the snippet in question:
var donateWindow;
// ######################################################################
// # Show the donation popup and open a window to paypal site
// ######################################################################
function showDonateWindow()
{
if (window.confirm("Question here"))
{
if (! (typeof(donateWindow) == 'undefined' || donateWindow.closed)) window.donateWindow.close();
window.donateWindow = window.open("http://somesite.com/","tabName");
}
}
Any help on this would be very appreciated. It would seem no matter what I do window.open returns the value "undefined".
My goal is to have a popup shown, but if one is already open it should just replaced the old one. This works as expected in FF, but for the life of me I can not get it going in Chrome.
Why are you trying to close existing window before open a new one? you don't need to do that.
if you just use the same name for window when you open it, it will replace the existing one if there is.
this means you don't need to look for if there is an opened window.
function showDonateWindow()
{
if (window.confirm("Question here"))
{
window.open("http://somesite.com/","donateWindowName");
}
}

Call Silverlight method from Javascript when it's ready

I have a page that loads another window on button click. The loaded page has silverlight control on it, so it takes some time to load and get prepared before it can receive javascript calls.
What I need to do is to call a particular method of silverlight object right after the silverlight plugin gets loaded and is ready to interact with me.
Now, if the pop-up page was already opened then the code would be like that:
var slWin = window.open('PopupPage.html', 'WindowName');
var elem = slWin.document.getElementById('slControl');
elem.Content.SlObject.MethodA();
This works when the window is already opened because the control is already loaded and ready. I need to modify this code to handle the situation when the elem need some time to be prepared.
I tried to use jQuery's ready and load methods to add handlers to corresponding events, but with no particular lack. Here's the full snippet:
var slWin = window.open('', 'WindowName');
var elem = slWin.document.getElementById('slControl');
if (elem == null) {
slWin.location.href = 'PopupPage.aspx';
// this branch doesn't work
$(slWin).load(function () {
elem = slWin.document.getElementById('slControl');
elem.Content.SlObject.MethodA();
});
}
else {
// this branch works fine
elem.Content.SlObject.MethodA();
}
How do I solve this issue? I don't mind jQuery solutions.
This error is happening because the Silverlight object is not fully loaded when you are trying to access it.
Try to use the "onload" event of the silverlight object to dectect when it's ready to use. Here you have a link to the MSDN documentation:
http://msdn.microsoft.com/en-us/library/cc838107(v=vs.95).aspx
Hope it helps. :)

Categories