Dynamic HTML: The Definitive Reference, 2rd Ed.Dynamic HTML: The Definitive ReferenceSearch this book

5.2. Writing to Other Frames and Windows

You can also use the document.write( ) method to send dynamically created content to another frame in a frameset or to another browser window previously opened by a script in the same page. In this case, you are not restricted to only one call to document.write( ) per page; you can open an output stream to another frame or window and keep dumping stuff into it until you close the stream with document.close( ).

All you need for this kind of content creation is a valid reference to the other frame or window. How you generate the frameset or secondary window influences this reference.

5.2.1. Framesets and Frames

A typical frameset document defines the physical layout of how the main browser window is to be subdivided into separate panels. Framesets can, of course, be nested many levels deep, where one frame loads a document that is, itself, a frameset document. The key to writing a valid reference to a distant frame is knowing the relationship between the frame that contains the script doing the writing and the target frame.

The most common frameset structure consists of one frameset document and two to four frames defined as part of that frameset (you can have more frames if you like, but not everyone is fond of frames). Ideally, you should assign a unique identifier to the name attribute of each <frame> tag.[6] Example 5-3 is a basic frameset document that assigns a name to each of the three frames and loads an efficient local blank page into each frame. The technique used here is to invoke a function, blank( ), that exists in the frameset (parent) document. In each case, the javascript: pseudo-URL is applied to the newly created frame. From each frame's point of view, the blank( ) function is in the parent document, hence the parent.blank( ) reference. The 100-pixel wide frame down the left side of the browser window is for a navigation bar. The right portion of the window is divided into two sections. The upper section (arbitrarily called main) occupies 70% of the column, while the lower section (called instrux) occupies the rest of the column.

[6]While XHTML 1.0 deprecates the name attribute for the frame element, older browsers ignore the id attribute. Due to the massive volume of framed web content that uses only the name attribute, browsers will support this attribute for many years to come. In the meantime, it is perfectly acceptable to assign the same identifier to a frame element's name and id attributes. This does not confuse scripts or link and form targets on any browser, and also validates as transitional XHTML 1.0.

Example 5-3. A simple three-frame frameset with blank pages written to each frame

<html>
<head>
<script language="JavaScript" type="text/javascript">
<!--
function blank( ) {
    return "<html></html>";
}
//-->
</script>
</head>
<frameset cols="100,*">
    <frame name="navBar" src="javascript:parent.blank( );">
    <frameset rows="70%,30%">
        <frame name="main" id="main" src="javascript:parent.blank( );">
        <frame name="instrux" id="instrux" src="javascript:parent.blank( );">
    </frameset>
</frameset>
</html>

Now imagine that a modified version of Example 5-2 is loaded into the main frame. The job of the script, however, is to write the dynamic content to the frame named instrux. To accomplish this, the reference to the other frame must start with the parent document (the frameset), which the two frames have in common. Example 5-4 shows the modified page that goes into the main frame and writes to the instrux frame. The two small changes that were made to the original code are highlighted.

Example 5-4. Writing dynamic content to another frame

<html>
<head>
<title>Welcome Page</title>
<script language="JavaScript" type="text/javascript">
// create custom page and replace current document with it
function rewritePage(form) {
    // accumulate HTML content for new page
    var newPage = "<html>\n<head>\n<title>Page for ";
    newPage += form.entry.value;
    newPage += "</title>\n</head>\n<body bgcolor='cornflowerblue'>\n";
    newPage += "<h1>Hello, " + form.entry.value + "!</h1>\n";
    newPage += "</body>\n</html>";
    // write it in one blast
    parent.instrux.document.write(newPage);
    // close writing stream
    parent.instrux.document.close( );
}
</script>
<body>
<h1>Welcome!</h1>
<hr>
<form onsubmit="return false;">
<p>Enter your name here: <input type="text" name="entry" id="entry"></P>
<input type="button" value="New Custom Page" onclick="rewritePage(this.form);">
</form>
</body>
</html>

If, on the other hand, you simply want to load a different document from the server into the instrux frame, you can use a scriptless HTML link and set the target attribute to the instrux frame. A script in main can also specify a document for the instrux frame as follows:

parent.instrux.location.href = "nextPage.html";

5.2.2. Secondary Windows

Browser object models provide facilities for not only generating a new browser window, but also setting the window's size and (in Version 4 browsers and later) its location on the screen. You can then use references to communicate from one window to the other, although the form of those references is quite different, depending on where the script is running.

The window.open( ) method that generates a new window returns a reference to the new window object. If you plan to communicate with that window after it has been opened, you should store the reference in a global variable. This reference is the only avenue that scripts may use to access the subwindow. Example 5-5 features a script for opening a new window and writing to it. In addition, it also takes care of a feature lacking in Navigator 2 (described in a moment), inserts a brief delay to allow the often sluggish Internet Explorer for Windows to finish creating the window before writing to it, and brings an already opened but hidden window to the front, if the browser supports that feature (Navigator 3 or later and IE 4 or later).

Example 5-5. Opening a new window and writing to it

<html>
<head>
<title>A New Window</title>
<script language="JavaScript" type="text/javascript">
// Global variable for subwindow reference
var newWindow;
// Generate and fill the new window
function makeNewWindow( ) {
    // make sure it isn't already opened
    if (!newWindow || newWindow.closed) {
        newWindow = window.open("","sub","status,height=200,width=300");
        // handle Navigator 2, which doesn't have an opener property
        if (!newWindow.opener) {
            newWindow.opener = window;
        }
        // delay writing until window exists in IE/Windows
        setTimeout("writeToWindow( )", 500);
    } else if (newWindow.focus) {
        // window is already open and focusable, so bring it to the front
        newWindow.focus( );
    }
}
function writeToWindow( ) {
    // assemble content for new window
    var newContent = "<html><head><title>Sub Window</title></head>\n";
    newContent += "<body>\n<h1>This is a new window.</h1>\n";
    newContent += "</body>\n</html>";
    // write HTML to new window document
    newWindow.document.write(newContent);
    newWindow.document.close( ); // close layout stream
}
</script>
</head>
<body>
<form>
<input type="button" value="Create New Window"
 onclick="makeNewWindow( );">
</form>
</body>
</html>

Example 5-5 shows that the reference to the subwindow (stored in the newWindow global variable) can be used to call document.write( ) and document.close( ) for that window. The newWindow object reference is the gateway to the subwindow.

A script in a document loaded into a subwindow can communicate back to the window or frame that spawned the new window. Every scriptable browser (except Navigator 2) automatically sets the opener property of a new window to a reference to the window or frame that created the window (recent browsers also set this property to windows launched by a and form element target attributes). One of the workarounds in Example 5-5 creates and sets this property for Navigator 2, so you can use it across the board. Therefore, to access the value property of a form's text box (named entryField) located in the main browser window, you can use the following script statement in the subwindow:

opener.document.forms[0].entryField.value

Remember that opener refers directly to the window or frame that spawned the subwindow. If you need to access content in another frame in the host window's frameset, your reference must traverse the object hierarchy accordingly:

opener.parent.otherFrameName.document.forms[0].someField.value


Library Navigation Links

Copyright © 2003 O'Reilly & Associates. All rights reserved.