The first technique for creating persistent data that we’ll be looking at involves storing the data in a frameset. As we’ll see, this is a relatively simple technique; however, it has several drawbacks. Chief among these is the requirement that your page use frames; furthermore, you must rely on the user not only to have a frames-capable browser, but to stay within your frames when viewing your site.
Your first reaction may be to wonder how frames have anything to do with what we’ve been talking about so far in this article. Surprisingly, frames provide the most direct means of circumventing the problem we encountered at the end of the last section! Since any JavaScript variable associated with a Web page is destroyed when the page is no longer loaded in the browser, any method that would allow us to make data persist even after the page is no longer loaded would have to provide for someplace else for that data to be stored.
Each frame in a frameset contains, as far as the browser is concerned, a separate document. The frameset itself is also considered a document by the browser, and as such can have JavaScript variables associated with it. In a frames-based site, the same frameset document is likely to remain loaded all the time, while the documents loaded into the frames (which I will refer to as framed documents) will be constantly changing. Storing data in any of the framed documents is of no use since as soon as the next document is loaded, the data will be destroyed. But the frameset itself is a great place for storing data!
The basic mechanics of the solution can be illustrated by the following steps:
Those readers who were paying especially close attention when I explained why JavaScript variables are destroyed when their “owner” documents are unloaded may wonder why the ability to access JavaScript variables in the frameset (or, in fact, any other document loaded simultaneously by the browser) is not considered a security risk. Well, the browsers impose the limitation that the JavaScript contained in a document can only interact with other documents that have been loaded from the same Web server, or host. This effectively prevents a Web site from stealing data that you may have entered into a form on another Web site; however, this could be a matter of some concern if you share your Web server with several other Web sites!
Referring to the four steps outlined above, I’ll now discuss the actual JavaScript code involved.
In step 1, we wish to create a JavaScript variable in the frameset document. Since we don’t want to assign it a value just yet, we simply use the following code:
var variableName;
In step 2, we write data to the JavaScript variable in the frameset from the framed producer document. Recall that a JavaScript variable in the current document can be assigned a value using the following code:
variableName = valueToStore;
Setting a variable in the frameset from within a framed document is very similar, and requires only that the variableName be prefixed with a reference to the frameset document as follows. Recall that to make a link in a framed document replace the entire frameset instead of just the framed document, you add TARGET=”_parent” to the tag. In JavaScript, to make reference to the enclosing frameset of a framed document, you likewise refer to the parent:
parent.document.variableName = valueToStore;
This works exactly the same way as links between frames. The frameset document is referred to in JavaScript as the parent document of any framed document it contains.
Step 3 doesn’t require any special code, just a link from the producer document to the consumer document. Any confusion on this point will be cleared up by the practical example below.
In step 4, we now wish to access the data in the variable that was created in step 1 and assigned a value by the consumer document in step 2. The fact that we are accessing it from a new document makes no difference. The new document is still contained in the frameset, and as such the reference to the variable remains the same. So if we wanted to display a message box containing the stored value, the code would simply be the following:
alert( parent.document.variableName );
Okay, all this stuff about JavaScript variables, producer/consumer documents, and storing data in framesets may seem pretty wild and crazy, especially if you’ve never come across a situation where you might need this stuff. Since most people I know learn best by example, we’ll finish up with a fully-developed (but simple!) application of the techniques discussed in the article so far.
Let’s return to the garage band we introduced back at the beginning of the article. We’ll implement the mailing list form we discussed, along with the confirmation page (which is the whole point!).
First, before we tackle the fancy stuff, let’s consider a basic form that will allow a user to submit his or her e-mail address. This is basic HTML, so there shouldn’t be anything too surprising here:
<form action="maillist.cgi" method="POST"> Enter your e-mail address: <input name="e-mail" type="TEXT" /> <input type="SUBMIT" /> </form>
TIP: This form assumes that you have a CGI program called “maillist.cgi” installed on your Web server for processing the form data. If you would like to try this example on your own, but don’t have CGI facilities (most people don’t!), let me recommend using the free form-submission service provided by Response-O-Matic. If you want to set up a basic form that sends its results to your e-mail address, I highly recommend this service. It is much more reliable than the commonly-used “mailto:” method that you may have seen, and there is no programming required!
Now, the point of this exercise is to add a confirmation page that will appear before the information is actually submitted. This will involve passing the e-mail address entered by the user to the confirmation page, which will display it for approval by the user, and then finally submit it. As we’ve seen, we’ll need to put our form into a frameset in order to pass the e-mail address from one page to the other. Here’s the code for a our frameset document:
<HTML> <HEA> <TITLE> Sign up to our mailing list! </TITLE> <SCRIPT LANGUAGE="JavaScript"> <!-- // Create an empty variable var emailvar; // --> </SCRIPT> </HEAD> <FRAMESET ROWS="50,*" BORDER=0> <FRAME SRC="header.html" NAME="header" FRAMEBORDER=0 SCROLLING=NO NORESIZE> <FRAME SRC="form.html" NAME="form" FRAMEBORDER=0> <NOFRAMES> Your browser must support frames, sorry! </NOFRAMES> </FRAMESET> </HTML>
The “header” frame we’ll use for a title that will stay visible throughout the process (I won’t even bother showing the code for this until the very end), while the “form” frame is where the real action will happen. The only special code required is a tiny script that creates the variable we will be using. Notice that is is simply created, not assigned a value. That will be up to the form document (the producer).
The two steps remaining are the big ones. First, we will modify our form so that, instead of submitting the data, it will store the value using the variable in the frameset and then load the confirmation page. First, let’s look at our modified form:
<form action="confirm.html" method="GET"> Enter your e-mail address: <input name="email" type="TEXT" /> <input type="SUBMIT" /> </form>
The changes to our form have been hilighted above; let’s review them here. First of all, since we won’t be submitting the information to our CGI program just yet (that will be done by the confirmation page), we put the URL of the confirmation page in the ACTION attribute. We also changed the form submission METHOD from “POST” to “GET”. When the form is submitted, the data actually will be sent to the Web server, but since the ACTION attribute refers to just simple HTML page, that submitted information will not be processed. Instead, the browser will simply get the confirmation page (using the GET method).
But before that happens we want the e-mail address entered to be stored in a variable in the frameset document. This is what the onSubmit attribute will do for us. This attribute has been set to trigger the JavaScript function storeVar() just before “submitting” the form (which in this case is simply advancing to the confirmation page).
So it’s up to storeVar() to grab the e-mail address entered by the user and store it in a variable in the frameset. The code for this function (which should be placed in the document header, between <HEAD> and </HEAD>) is as follows:
<SCRIPT LANGUAGE="JavaScript">
<!--
function storeVar() {
// Store the value from the form in the variable
parent.document.emailvar = document.maillistform.email.value;
}
//-->
</SCRIPT>
The JavaScript here should be familiar if you’ve been following along from the beginning. We have created a function called storeVar() that, when triggered, does the following:
Store the value taken from the current document, in the form named maillistform, in the field named email into the variable in the parent document called emailvar.
That does it for our producer document. The second, and final big step is to write our consumer document, the confirmation page. This page has two roles:
1. Display the value entered by the user on the first page, requesting confirmation that it is indeed correct.
2. When that confirmation is given, submit the form to the Web server.
Let’s take this one step at a time. First, we need to somehow insert the value stored in the variable in the frameset into the text of the confirmation page. This is done using the JavaScript document.write() function. Have a look at the code:
<P>The address you entered was: <SCRIPT LANGUAGE="JavaScript"> <!-- document.write(parent.document.emailvar); //--> </SCRIPT>
The hilighted line is the important one, and reads as follows:
write to the current document the value of the variable emailvar in the parent document.
Note that, unlike previous scripts we’ve seen that belonged in the header of the document, this one sits right in the middle of the document body. The reason for this is that we aren’t setting up a function to be triggered later on. We’re writing a piece of JavaScript that we want executed as the page is loading, specifically at this point in the page.
The last detail is to figure out how to submit the e-mail address from the confirmation page. Obviously, to submit data we’ll need a form; however, we don’t want another full-blown form on the confirmation page. All we want the user to see is a question asking whether or not the value he or she entered was correct, and two buttons: “accept” and “cancel”. We don’t want another text field that would allow the user to further modify the value.
To solve our problem, we’ll use a hidden form field. This is a form field just like a normal text field, except that it is totally invisible to the user! When the page loads, we’ll use a little bit of JavaScript to write the e-mail address (taken from the variable in the frameset) into the hidden form field. The only visible parts of the form will be the two buttons, “accept” and “cancel”, but when the form gets submitted, the e-mail address in the hidden field will be submitted just as if the user had typed it into a text field.
Here’s the code for the form, including the hidden field, the two buttons, and the JavaScript that assigns the stored variable value to the hidden field:
<FORM NAME="confirmform" ACTION="maillistform.cgi" METHOD="POST"> <INPUT TYPE=HIDDEN NAME="email"> <INPUT TYPE=SUBMIT VALUE="Accept"> <INPUT TYPE=BUTTON VALUE="Cancel" onClick="location='form.html'"> </FORM> <SCRIPT LANGUAGE="JavaScript"> <!-- // Assign the value of the stored variable to the hidden form field document.confirmform.email.value = parent.document.emailvar; //--> </SCRIPT>
With everything you’ve learned up to now, you should be able to understand pretty much everything that’s going on in this code. There are two things that bear mentioning, however.
First, the “Cancel” button has been set up so that when it is clicked, the JavaScript code “location=’form.html’” is triggered. This simply tells the browser to load form.html, to allow the user to enter another address. If you’d like the “Cancel” button to lead elsewhere, feel free to insert any URL you want in the place of form.html.
Second, the JavaScript once again appears in the body of the document, to be executed as the page is loading. It’s important that it appears after the form, since otherwise the JavaScript would be trying to set the value of a form field that does not yet exist! This could lead to some messy error messages, as you can imagine. Try it and see for yourself!
And that does it! We’ve built all the pieces of the puzzle! Use the links below to see the completed example in action, or to examine the finished code.