ColdFusion in Context: Back Channel to Server

Suppose you want to pass data between pages. Ignoring storage on the server, there are three classic ways to do this: write a cookie on one page and read it on another, add to a URL, and submit a form from one page to another. Further, one can draw inferences from the referrer URL, from the name of the current script, and from dynamic variations in target links and form fields. However, there is one more way not mentioned here: you can move form field data from another frame to another without actually submitting the form whose fields you're changing.

Caveat. This demonstration, as written, does not work with Firefox.

Suppose you want to get more information from the server without submitting the page to do it. You could use an IFRAME, but only one browser supports that. There is another way: use regular frames. This demonstration uses URL and form fields with frames to show how to query the server without redrawing the current page.

Make a Frameset

You'll need a frameset to hold the frames; call it welcome.cfm. There isn't much to a frameset. The most important thing to remember is that it must be defined in no-man's land between the end of the head and the beginning of the body.

The frameset rows parameter says to give the first frame all but 1 pixel of the available height. You may not even notice there is a second frame at first.

Name the frames so you can refer to them later. Let the first one scroll, but don't give the second one a scroll bar.

<html><head>
<title>Forum Welcome</title>
</head>

<frameset rows="*,1">
<frame name="asker" scrolling="auto" src="newuser.cfm">
<frame name="checker" scrolling="no" src="chkuser.cfm">
</frameset>
<body>
<noframes>
Oops; need frames!
</noframes>
</body>
</html>

Make an Entry Form

Call the entry page newuser.cfm. Begin by defining the code to tickle the other frame. You'll send the proposed username - a "handle" - to the other frame for verification. The function shown here sets the target, putting the handle in the URL, and then reopens the target in the other frame. (The page was already in that frame, but now you've called it again with a handle in the URL.)

<script language="javascript">
<!--
function askhandle()
{
var mytarget = 'chkuser.cfm?handle='+document.welcome.handle.value;
top.checker.document.location.href = mytarget;
return true;
}
// -->
</script>

The form is straightforward. The only nuance it contains is that when the user changes the handle field, onChange calls the function you've just defined. It feels like magic to be able to access form fields that haven't been submitted, but it works, and there are more spectactular things to come.

Welcome!  [For this demo, you can have any username except Frank.]
<p>
<form name="welcome" action="adduser" method="post">
<pre>
First/middle name.......Last name..............Jr....
<input type="text" name="fmname" size="27" maxlength="25">
<input type="text" name="lname" size="27" maxlength="25">
<input type="text" name="jr" size="7" maxlength="5">
</pre>
What username would you like to use?<br>
<input type="text" name="handle" size="17" maxlength="15" 
onChange="askhandle()" value=""> 
[feedback:]<input type="text" name="myhandle" value="">
<input type="text" name="myresult" value="">
<p>
What's your E-mail address?<br>
<input type="text" name="email" size="65" maxlength="60">
</form>

(The submit button has been left off; because, this demo has noplace to go.)

Make a Verification Page

Call the verification page chkuser.cfm. You already know how to write queries; so, this demo fakes it by saying that any username is OK except for "Frank", which is aready taken.

<cfif isDefined("url.handle")>
  <!--- Here's where your query would go --->
  <cfif url.handle is "Frank">
    <cfset rows="1">
  <cfelse>
    <cfset rows="0">
  </cfif>
<cfelse>
  username not provided; press back button to continue
  <cfabort>
</cfif>

Here is the most amazing thing in the demonstration. You can write back to the fields of the other frame using javascript. You navigate to the other frame through the parent. In the frameset, the other frame is called asker. The form you want to affect is welcome. The fields you want to change are myhandle and myresult.

<script language="javascript">
<!--
function tell()
{
parent.asker.welcome.myhandle.value = 
<cfoutput>'#url.handle#'</cfoutput>;
<cfif rows eq 0>
  result = 'seems OK for you to use';
<cfelse>
  result = 'is in use; try another';
</cfif>
parent.asker.welcome.myresult.value = result;
return true;
}
// -->
</script>

<body onLoad="tell()">

The demo displays the result in case you're skeptical.

<!--- In case anyone wants to look behind the curtain --->
<cfoutput>
handle: #url.handle#<br>
matching rows: #rows#
</cfoutput>

Run and Recap

Call welcome.cfm in the browser, begin to enter data, and look what happens when you change the proposed username. Comments regarding its suitability are displayed, placed there by the bottom frame. Because the query page is small (relatively speaking), even a real query shows no more than a blink and a bit of text in the status bar momentarily.

Extend this technique in other ways. The other frame can be made to pop up an alert box, if you'd rather see that. It can also be created with no visible output in case you don't want the user to see anything if she or he lifts the curtain. Replace the fake query with a real one to satisfy yourself that this technique works. Then extend it and talk about what you've done. =Marty=
[The underlying symbol used for greater-than and less-than in description of this tip has been changed to include a semicolon; failure to do this caused the browser to absorb the semicolon that should have been displayed after the first variable assignment in the tell() function when the tip was originally published. Also, the reference in the description to getuser.cfm has been changed to chkuser.cfm as indicated in the code.]
[This tip was written before Firefox was available. The caveat regarding Firefox was added later.]