JavaScriptingWindow to window communication

WAY BACK IN the very first installment of JavaScripting,1 I discussed using JavaScript to determine if a Web page was fully loaded into the browser. This discussion was presented in the context of a frames-based site where the controls in one frame drove the contents of another frame. The main problem with such a setup is how to make sure that the controlled frame is fully loaded before you act on it from the controlling frame. Recently, a client asked me to solve a similar problem, except instead of communicating between a set of frames in a single window, I needed to communicate between two or more actual windows.

No Problem?
You might be thinking, "No problem! Just open all your windows from one original window and then use the 'opener' property of each new window to refer back to the parent window. Right?" That will work, but only for Netscape clients. Unfortunately, most versions of Internet Explorer don't support the opener property at all. So, what we need is a browser-independent way of letting our windows talk to one another.

Of course, in a frames-based scenario there really isn't much of a problem: We simply refer to the parent object, and from there we can speak to any of our sibling frames/windows. Actual independent windows, however, present a unique problem. Specifically, if one window (which we'll call the "parent") opens another (the "child"), the parent has access to everything in the child window. (This includes JavaScript variables, functions, and objects, as well as the document itself.) On the other hand, the child window has no way to access anything in the parent unless the parent specifically gives it access.

How does a parent window allow its children to access its contents? Listings 1 and 2 provide the answer.

The Timing Problem
First, you have to overcome what I call "the timing problem." Simply put, before the parent can communicate reliably with a child window, the entire contents of that child window must be loaded into the browser and parsed into its Document Object Model (DOM) equivalent. For example, if the parent needs to access the third text field in the fourth form of a child window, you get an error if that form and field haven't been loaded and parsed into something that's accessible to JavaScript!

So, how do we check if a file is loaded and parsed? Well, you might be tempted to use the "onLoad" event handler. Unfortunately, true to it's name, this only tells you when a file is loaded; actually getting the information in the file parsed into a DOM equivalent can take several seconds more. The most reliable way I've found to check if a file is loaded and parsed is to place a "dummy" form at the end of my documents and then examine the length of the document.forms array. For example, if the main form occurs early in your document and you place a dummy form at the end, when the length of document.forms becomes greater than 1 you know that not only has the dummy form been loaded and parsed, but that everything before it (including your main form) has been loaded and parsed as well!

As an example of this, look at Listing 1. Near the bottom of this listing, we've got a button that, when clicked, invokes a JavaScript function that opens a new window. After this window is open, we call the makeLink() function to establish two-way communication between the new child window and its parent. Looking at the makeLink() function, you see that the first thing it does is check the document.forms.length property of the child window. If this property is greater than zero, we know that the form at the end of Listing 2 has been loaded and parsed. Because Web browsers load and parse files from top to bottom, we also know that everything else in the file is loaded and parsed. Now, we can change the child window's myParent JavaScript variable to contain a reference to the parent window, which gives us our two-way communication. On the other hand, if document.forms.length was not greater than zero, we would call setTimeout() and try to create our link again one second later.

The Generation Gap
At this point, the action moves to the child window. Before the child window can reliably communicate with its parent window it must ensure that the parent has set up the link back to it. Looking at Listing 2, you see that, at the top of the listing, there is a JavaScript variable named "myParent." Initially, this is set to "self." Of course, the window can't be its own parent! We are simply using self as a known flag value, something that we can check against over and over again. So, when the value of myParent becomes something other than self, we know that our parent has successfully established the two-way link.

We begin checking the state of our link by using the onLoad event handler. This handler is a function that simply compares myParent with self. If they are the same, we don't have a link and we use setTimeout() to try again two seconds later. If they are not the same, however, then we know that myParent now contains a reference to our parent window and we set the linked variable to true.

Testing the Link
To test the link, I've placed a simple form on the child page. If you type your first and last name into this form and then click the provided button, the passInfo() function will be called. This function first checks the linked variable to see if our link has been established. If not, it displays an alert that tells the user to try again in a few seconds. If the link has been established, it passes the entire form object to the showInfo() function in the parent window. This function simply extracts the information in the form object and displays it in an alert window.

Conclusion
In these two simple files, we've seen several interesting techniques. Arguably the most useful technique here is the ability to determine when an HTML file has finished loading. Over the years, I've found use after use for this little trick, and new uses seem to present themselves with each new project.

Almost as important is the ability to communicate in both directions between a parent window and its children. It's important to note that, after you establish this link you can use this window to window communication just as you would frame to frame communication. So, you can pass variables and objects, call functions, and make changes to a window's contents just as if you were working with a frames-based set of documents.

To use a very bad pun, this literally "opens a new window" of possibilities for your JavaScript code. Try out these techniques and let me know what uses you find for them!

Reference

  1. Disbrow, Steven W., "The timing problem: a solution for complex Web sites," Java Report, Vol. 3, No. 2, Feb. 1998, pp. 68–69.

About the Author

Steven Disbrow is the owner of EGO Systems, a computer consulting firm in Chattanooga, TN. He can be contacted at [email protected].