Closing children windows from Javascript - javascript

I have been searching high and low for a solution to my problem and can only find pieces of the puzzle with no way to connect them. I have a window (which it self is a child of the main window) that can open multiple other windows. I want the children windows to be closed when the parent is closed, sounds simple enough right?
Here is the dilemma, my parent window does a postback when opening the child so any array of handles (which are also objects) I keep does not persist. I have looked into serializing and de-serializing this array and storing it in a hidden field but that doesn't seem like the best solution. I also can not access the parent of the window doing the opening.
Aside from Javascript, the server side code is written in C# and I'm using asp.net. Is there any reasonable solution to this? I should also mention that the code I am working with was written by multiple different people long before I got to it so I would like to add to it rather than changing how most of it works.
Finally, I know it is typically a good idea to post my code on here but I am simply using var win = window.open to perform the window opening task.
Thank you.

OK, I then see 3 ways to get around that problem:
Don't use multiple browser windows, but style your page to show all the dialogues; as #Gats suggested. OK, that will somewhat limit you if you want the input of parent "windows" persistant while navigating in a child window.
Don't do a refresh postback to unload the parent. Use Ajax instead to send data to the application server
You can't store (window) objects, you only can store strings. When opening a window, you can give it a "target" name, and any other window.open with the same target (name) will use the already open one. With that, you can reference windows you didn't open yourself - and close them. See https://stackoverflow.com/a/563478/1048572

What about
var wins = [];
function newChildWindow(...) {
wins.push(window.open(...));
}
window.onuload = function() {
for (var i=0; i<wins.length; i++)
if (!wins[i].closed)
wins[i].close();
};

Related

Listen to event in another window

I created a window using var openedWindow = window.open(...).
I have a function which should listen to click event for a button in the new window, but it never fires.
Whenever I click btSearch button it should open another window and listen for #submitButton click event.
btSearch.Attributes["onclick"] = $#"
var openedWindow = window.open(myUrl, "", "toolbar=no,menubar=no,personalbar=no,width=650,height=399,scrollbars=yes,resizable=yes");
window.onModalExit(openedWindow);";
Function is aspx file
function onModalExit(modalWindow) {
$('#submitButton', modalWindow.document).ready(function () {
modalWindow.document.getElementById('submitButton').addEventListener('click', function () {
console.log('RETURNED CORRECTLY');
alert('Now');
});
});
}
you can send data from opened window to opener window via window.opener.postMessage() function.
Every window in a broswer is "isolated", that is there is no way for you to programaticly effect an other window.
That can be done only by the browser who is managing all those tabs. Or maybe by an installed extension for a browser, i suspect those have the power to inject stuff in the running pages probably
EDIT:
Now since that can not be done directly in any way that i know of, you could maybe:
Create a polling mechanism on the tab you want to read the value from
Store the value in some kind of server ( database, in-memory of a back-end etc )
Find a way to associate some kind of ids so you know what to look for.
So you will be transfering the value by taking a long way around PageA -> BackEnd -> PageB.
I am pretty condifent in saying that you can not effect/read from an other tab just by a plain page. You need something of higher layer, like the browser itself, or an extension that has the ability to inject/inspect pages, after a user has agreed to give permissions by installing the extension.
The only solution I see to solve your requirement, would be to use Sockets
But for this, you obviously need some kind of backend.

Unable to sort against array of objects in window.opener using javascript

from my first window (I'll refer to it as window 1) I'm opening a second window (window 2) using
var w = window.open("", "");
From within window 2 I'm referencing and manipulating an array defined in window 1 using code like
window.opener.object2[0].drivedistance = driveDistance;
This code works fine. However, before displaying the results of this array in window 2 I need to sort it. My attempt at sorting:
window.opener.objects2.sort(compareFunc)
function compareFunc(a, b){
return (a.drivedistance - b.drivedistance)
}
If I use the same method in jsfiddle without calling from a remote window it seems to work fine.
http://jsfiddle.net/98Q4D/10/
When I step through the code I can see that it's executing the code in compareDriving. No exceptions are being thrown. However, after it gets done calling compareDriving the array is not sorted. I don't know if maybe this is some kind of a security issue because the array I'm sorting exists in window 1, but my javascript is in window 2? Any ideas on why this sort code isn't working would be much appreciated.
Based on comments I put together a jsfiddle of the issue that seems to demonstate it well. To be clear on the final solution, I need page 1 to be the repository of the collection, but I need page 2 to initiage the logic that causes the collection on page 1 to be sorted.
http://jsfiddle.net/mexP6/26/
Bizarre. After playing with this some more it looks like I may be able to accomplish what I want by passing the sort function a handler that exists on page 1 instead of page 2. But when I run the function remotely on page 2 it sorts in the inverse order as when I run it from page 1. I can probably play with this to get it to work, but would still appreciate any suggestions on best practices. Here's my latest fiddle of my findings.
http://jsfiddle.net/mexP6/23/
Keep in mind that you'll need to enable popups to test any of these as I'm working with popup functionality.
Edit. I'm finding that cross-browser results are very spotty on the last jsfiddle. A buddy of mine tried it in chrome and it worked for him. I tried it in my chrome and the results aren't sorted. IE sorts in reverse. I haven't gotten firefox to work at all. Any help on a method to accomplish cross window sorting that is cross-browser compatible is what I think I'm really after here. Thank you for any and all answers.
I think you are running into the rules about which scripting actions are allowed between separate windows, which will obviously differ between browsers. If you consider your initial example (below), you are executing a method (sort) on an object (the array) that lives in the parent window, but you are passing it a function from the popup window.
window.opener.objects2.sort(compareFunc)
function compareFunc(a, b){
return (a.drivedistance - b.drivedistance)
}
I generally find it is best to allow the parent window to handle any modification of its own data. This is essentially what you tried to do in your most recent jsfiddle attempt (http://jsfiddle.net/mexP6/23/), but it was thrown off by a spelling error in the name of the sorting function. You wrote "compareFuncFromMainPag" instead of "compareFuncFromMainPage". This would have worked otherwise because you were asking the sort method to sort the array using a compare function that also belongs to the parent window.
Personally, I would make this even more explicit by only calling functions on the parent window from the popup window. Those functions in the parent window would perform all of the data manipulation. Consider this modification of your latest jsfiddle as an example of what I'm suggesting:
http://jsfiddle.net/jarbirdy/dUMMw/8/

How can a Javascript parent window send data to popup window?

I have been writing a browser based application (or rather, rapid prototyping an application) using HTML and Javascript. I would like the main window to be able to display popup windows with dynamic data. However, I cannot figure out how to push data from a parent window to a popup window in Javascript. Note, I am working with the assumption that the application may be used in "offline" scenarios, so all dynamic data should be coming from the main window.
Ideally, I'd like to write
var popup = window.open("popup.html", someidentifier, "");
popup.document.getElementById("SomeIdInPopupHtml").innerHTML = "1,2,3,4";
However, the getElementById function returns NULL. How can I push data to popup windows from a parent window?
Is the popup serving content from a different domain than the parent? If so, the short answer is you can't.
The long answer is that you can sent the popup's href fragment (i.e. the part after the # in protocol://server/path?query#fragment). If the content in the popup knows to check its fragment for changes, then you can pass data to it.
If it's from the same domain then your code should work, as long as an element with that id exists.
However, the getElementById function returns NULL.
Because popup.html hasn't loaded yet. If you want to interact with content from the document, you'll have to call back later when it has finished loading.
For completely dynamic popups, open them with a blank URL and popupwindow.document.write their content into them. For co-operatively-scripting popups loaded from a separate document, have the child document call its parent when it is ready to be accessed. Or just use in-page pop-up divs which are typically less annoyance, both for you as a coder and for the end user.
Let me start off by presenting a possible solution that I just experimented with. I would like to encourage feedback and better solutions, however...
Its not very neat, but I can append GET-style query parameters to the source URL of the popup:
var popup = window.open("popup.html?" + identifier, somename, "");
Now in my particular situation, the popup is a view to some model identified by a unique ID, so the popup window can ask for the parent window for data related to that ID:
var model = window.opener.getModel(document.location.href.split("?")[1]);
do_something_with_model(model);
This strategy won't work in all cases, especially when the data is not easily marshaled into the getModel() implementation. However, in my case, I think this approach may work.
I'd appreciate feedback on this strategy. Thanks!
When the user clicks on your link to open the popup window pass a query string to it and then react to that value with your server side code.

JavaScript objects and persistence through dialogs

Rather simple question here. I want to create an JS object that has a property, say, name. I want to create that object and be able to use it throughout my page. For example, what I have now doesn't work:
var item = new Object();
function makeItem(title) {
item.name = title;
}
Inside a modal dialog:
makeItem("test");
alert(item.name); // returns "test"
Once I close the dialog, however, all of the information related to item is gone. For example, I can't go ahead and see if item.name contains anything the next time I try to create the same dialog.
Nothing is currently inside a document.ready().
Clearly I'm not fully capturing the idea of the DOM. Would you mind enlightening my poor brain?
As Jon correctly states, more details and code would help understanding your situation.
From your symptoms though I'm guessing you have a dialog.html page with the script trying to "makeItem" and this dialog.html is loaded in a frame or even a separate browser window/tab each time you "open the dialog".
A little theory
In browsers all JavaScript objects and code "belong" to one of the open "pages". A page may be open as a top-level page in a browser tab or a separate window, or in a frame (in which case it appears to be part of its parent page, but its JS is still separated from the parent).
Each open page its own "global object", which is commonly referred to as window. The global functions and variables you define at the top level in a <script> are attached as properties on this global object.
When you open the same page twice (simultaneously -- in two tabs side by side -- or closing the first one before opening the second copy), each copy gets its own global object, completely separate code and objects.
Generally when a page is closed, the global object of that page and all its properties (including any objects and functions) are destroyed.
This is why item in your example loses its properties when you close and re-open the dialog (assuming my initial guess was correct).
References to another window
The proper fix to your problem depends on what you're trying to achieve.
If you need to communicate from the opener page to the opened dialog and back, you can save the reference from the window.open() call:
var w = window.open(...dialog URL...);
After the dialog is loaded, w will point to the dialog's global object and you'll be able to poke it. Similarly, from the dialog you can access the global object of the page that opened the dialog via window.opener.
So you can create item in the opener's context by putting the following in the dialog's <script>:
opener.item = {title: "test"};
...and it will live as long as the opener page.
Real persistence
If you need real persistence (e.g. across browser restart), your only options until recently were cookies or server-side storage. In modern browsers you can use Web storage (localStorage, sessionStorage objects) for that.

Best way to propagate opener variable across page navigation?

Application that I'm working on has multiple modules. Two are of a concern - main module and module that I write. And I have to call a function on window that contains main module and the problem is that I have to call that function not from page that is opened by parent webmodule, but from page to which user navigates from this page.
Basically first page presents just some query forms, lets user to make some query, and second holds query results, and I am supposed to update contents of parent page based on these results.
Navigation goes like that
Main module
First page of my module (i have main module page as an window.opener variable.
Second page of my module (and I would like to be able to open this page in the same browser window that the first one is opened)
And I would like to have as free navigation as possible - like opening query results in new tab, going back changing query parameters, making new query, etc. I would also like to present user query forms on page that displays results and let them to refine this query, and still be able to update main module.
I was thinking of following solutions:
Using AJAX to load query results to first window, but I would like to have this app as simple as possible, and AJAX is not simple ;)
Spawning new window on every request and doing code like var mainModule = opener.mainModule. Which is evil.
Embedding query results in a frame or iframe, but I havn'e got the slightest idea on how to inject main module window javascript variable into frame or iframe.
If being able to navigate in tabs is a requirement, I think you'd have to nix the idea of using a JavaScript opened window system. Because the opener property is definitely lost in Firefox, Safari, and most browsers, when you navigate to a different window. A new tab disturbs the neat sandbox.
Not being a requirement, per your comment, I think you can use either of 3 methods:
Parent-Child window communication-- which I will take up
next;
XMLHTTP Requests (a.k.a.
AJAX); or
iFrames (the old way
to remote to the server :)
I'll take the Parent child communication angle, here, since you seem to be most comfortable with it.
Inter-navigation in a "Child" window is easy.
any link on the page loads in the child and shares the same "opener".
the parent can reload a different page and it shares the same opener.
There will be a parent-listener function in the child;
The child will have a separate function to talk to the parent.
The parent will have one or more child listeners, depending on how
generic, or specific your needs.
I've updated (not completely) an article I wrote years ago, to let you play around with the windows and to actually do a minimal form submission. The communication alerts are rather verbose; but you will have no doubt as to who is communicating what to whom. The first child is annoyingly opened onload. But there is a link on the page to change the child to a server-generated form.
JavaScript: Beyond Parent Child Windows
EXAMPLE CODE SNIPPETS:
A Link:
open a window from link
Link Listener:
The event listener and target property are set up in the head of the document, in JavaScript that executes onload:
var mywin; //global variable for best results
//XDOM - normalizes browser differences:
var openingLink = XDOM.getElementById('newwinlink');
openingLink.target = "newWin"; //important!
XDOM.addListener(openingLink, 'click', function(e){mywin=window.open('','newWin','width=400,height=400,resizable,scrollbars');if (!mywin.opener){mywin.opener = self;}return true}, false);
Child Document - Parent Listener:
function parentListener(pmsg)
{
alert("I'm the child, and I just received the following message from my parent:\n\n" + pmsg);
}
Child Document - Talk to Parent:
function talktoParent()
{
if (self.opener!=null) {
opener.childListener("Hi from child window!");
} else {
alert("no opener... sorry, can't talk now");
}
}
Parent Document - Child Listener:
function childListener(cmsg)
{
alert("I'm the parent. Just received the following message from my child:\n\n" + cmsg);
//send back a message to the child, mywin...
mywin.parentListener("Hi, back, from parent window!");
}
These are simplistic. But you can see opener continuity, navigation, and communication between server-side postbacks and the Parent at the link provided above.
Again the downside is that opening any of these in another tab will lose the connection to the parent. Try it over on the page that I sent you to. I believe the child is set to alert you that it is disconnected from its "opener".
Feel free to ask questions, jb.
iirc, even after you navigate away from the original document in a window opened by window.open, window.opener is still available.

Categories

Resources