Passing Simple Variables to ColdFusion
In the "Serializing Packets with WddxSerializer" section of this chapter, you learned about a rather sophisticated way to pass complex, multifaceted data from JavaScript to ColdFusion: by serializing the data into a WDDX packet and posting it to the server. If you only need to pass simple values (such as strings or numbers) to the server, you can use simpler methods.
Passing Variables as URL Parameters
The simplest method of passing variables to ColdFusion is to simply pass them in the URL.
1. | Construct a URL that includes the values you want to pass as URL parameters, using the &name=value format you already know and love. If a value may include spaces, slashes, or any other "funny" characters (basically anything other than numbers and letters), you must use the escape() function to escape the characters; it does the same thing that URLEncodedFormat() does in CFML. |
2. | Tell the browser to navigate to the new URL, using the document.location.href property or the document.location.replace() function. |
The following snippet would create a function that causes the browser to navigate to a fictitious ColdFusion page called ShowFilms.cfm, passing URL parameters called Name and Rating in the URL:
NOTEThis snippet is just meant to demonstrate the syntax you would use; it doesn't necessarily make any real-world sense. If you were simply collecting a name and age from the user, you would probably just use a norma225 form to collect the information.
function loadPageBasedOnAge(name, age) {
var rating, url;
// Decide on a rating, based on the value
// of the JavaScript age variable
if (age < 13) {
rating = "G";
} else if (age < 18) {
rating = "PG-13";
} else {
rating = "R";
}
// Construct a new URL, passing the rating to ColdFusion
var url = "ShowFilms.cfm?Name=" + escape(name) + "&Rating=" + rating;
// Navigate to the new URL
document.location.href = url;
}
Passing Variables as Form Parameters
Another way to pass simple values is to use hidden form fields. To place a simple value (that is, any value that can be straightforwardly expressed as a string) into a form field, just use JavaScript code like the following, where myValue is the JavaScript value that you want to pass to the server:
If you wish, the form can then be submitted programmatically, like so:
document.forms[0].MyHiddenField.value = myValue;
Listing 17.12 creates a page that subjects the user to a short, three-question quiz about some important dates in his or her life. The user is given only ten seconds to answer each question. The time remaining ticks off visually, at tenth-of-a-second intervals (Figure 17.7).
document.forms[0].submit();
Figure 17.7. A JavaScript-based timer is used to time the user's response.
[View full size image]

Figure 17.8. A JavaScript-based timer is used to time the user's response.
[View full size image]

Listing 17.12. TimedFormSubmission.cfmPassing JavaScript Variables as URL Parameters
When this page first appears in the browser, the onload event calls the initPage() function. Within initPage(), a global variable called msMomentPageWasLoaded is set to the current time (according to the browser machine's clock, and expressed as the number of milliseconds since midnight on January 1, 1970). In addition, the window.setInterval() method is used to create a sort of internal timer which executes the fillTimeElapsed() function once every 100 milliseconds (that is, ten times per second).Within fillTimeElapsed(), a global local variable called msTimeElapsed is incremented by 100 each time the function is calledis calculated by subtracting the value in msMomentPageWasLoaded from the current time (again, in milliseconds). The msTimeElapsed, thus keeping track of the approximate number of milliseconds that have passed since the page first loaded. variable thus holds the number of milliseconds that have elapsed since the initPage() executed, which in turn is the number of milliseconds that have passed since the page first appeared in the browser.The number of elapsed milliseconds is stored in the hidden form field named TimeElasped; this value will be available to ColdFusion as a normal FORM variable when the form is submitted. In addition, a formatted version of the number is displayed by setting the inn218 property of the <SPAN> element called elSecsElapsed. The getElementById() syntax used here can be used to get or set the properties of any scriptabl218 element; the exact properties available will vary from browser to browser. The inn218 property used here is supported by IE 4 and above and Netscape 6 and above (or other Mozilla-based browsers).If the number of elapsed milliseconds exceeds the maximum number of milliseconds (in this example, 10,0000, or ten seconds), the timer is cleared using window.clearInterval(). The form is then submitted using the form's submit() method.The rest of the code is relatively straightforward ColdFusion code that uses a structure called SESSION.TimedResponses to remember each user's responses as they encounter the three parts of the quiz. The structure is made up of smaller sub-structures, each containing a TimeElapsed property, an IsAnswered property that indicates whether the user provided an answer in time, and an AnswerDate property which is the user's actual response to the question (if any).
<!---
Name: TimedFormSubmission.cfm
Author: Nate Weiss and Ben Forta
Description: Demonstrates passing JavaScript
variables to ColdFusion in the URL.
Created: 02/01/05
--->
<!--- Filename of the current ColdFusion page --->
<cfset CurrentPage=GetFileFromPath(GetBaseTemplatePath())>
<!--- Keep track of the responses on the server --->
<cfparam name="SESSION.TimedResponses"
type="struct"
default="#StructNew()#">
<!--- We'll ask the poor user one of these questions at random --->
<cfset Messages[1]="When is your spouse's or partner's birthday?">
<cfset Messages[2]="When is your anniversary?">
<cfset Messages[3]="When is your ColdFusion application going to be done?">
<!--- Maximum number of milliseconds allowed per answer --->
<cfset MaxMillisecondsPerPage=10000>
<!--- If the form is being submitted... --->
<cfif IsDefined("form.TimeElapsed")
AND IsDefined("form.AnswerDate")
AND Val(form.TimeElapsed) GT 0
AND IsDefined("URL.MessageNum")
AND URL.MessageNum GT 0
AND StructCount(SESSION.TimedResponses) EQ (URL.MessageNum - 1)>
<!--- Record the number of seconds elapsed --->
<!--- Don't allow the user to overwrite the number by reloading the page --->
<cfif IsDate(form.AnswerDate) OR (form.TimeElapsed GTE MaxMillisecondsPerPage)>
<cfif StructKeyExists(SESSION.TimedResponses, URL.MessageNum) EQ False>
<!--- Create a structure that holds user's answer and elapsed time --->
<cfset AnswerStruct=StructNew()>
<cfset AnswerStruct.TimeElapsed=form.TimeElapsed>
<cfset AnswerStruct.IsAnswered=IsDate(form.AnswerDate)>
<cfif AnswerStruct.IsAnswered>
<cfset AnswerStruct.AnswerDate=form.AnswerDate>
</cfif>
<!--- Save structure in SESSION.TimedResponses by the message number --->
<cfset SESSION.TimedResponses[URL.MessageNum]=AnswerStruct>
</cfif>
</cfif>
</cfif>
&l233>
<head>
<title>Surprise Quiz</title>
</head>
<h2>Surprise Quiz</h2>
<!---
If all the messages have been responded to
Display the results of the quiz --->
<cfif StructCount(SESSION.TimedResponses) GTE ArrayLen(Messages)>
<body>
<!--- Display message --->
<!--- In a real application, the user would succeed sometimes... :) --->
<p><strong>Wow, you failed the quiz miserably.</strong><br>
Here are the response times for your answers:<br>
<ol>
<!--- For each of the user's answers --->
<cfloop from="1"
to="#ArrayLen(Messages)#"
index="i">
<cfoutput>
<li>
<!--- This is the message user was responding to --->
#Messages[i]#<br>
<!--- If the user provided a response --->
<cfif SESSION.TimedResponses[i].IsAnswered>
Answered "#SESSION.TimedResponses[i].AnswerDate#" in
#NumberFormat(SESSION.TimedResponses[i].TimeElapsed / 1000, "9.99")#
seconds<br><br>
<!--- If the user wasn't able to answer the question --->
<cfelse>
[was not answered in time]
</cfif>
</li>
</cfoutput>
</cfloop>
</ol>
<!---
Erase the SESSION.TimedResponses variable
The quiz will start over if the page is reloaded
--->
<cfset StructDelete(SESSION, "TimedResponses")>
<!--- Display message --->
<p>Dude (or dudette), you are in <strong>so much trouble</strong>.
Like, good luck tonight.<br>
<!--- Link to try again --->
<!--- Because SESSION.TimedResponses was erased, quiz will begin again --->
<p>If you want, you can <a href="TimedFormSubmission.cfm">try again</a>.<br>
<!---
If not all the questions have been responded to,
Provide a simple form interface for providing an answer
--->
<cfelse>
<!--- Determine the message number to display now --->
<cfloop from="1"
to="#ArrayLen(Messages)#"
index="ShowMessageNum">
<cfif NOT StructKeyExists(SESSION.TimedResponses, ShowMessageNum)>
<cfbreak>
</cfif>
</cfloop>
<!--- Get the text for the message --->
<cfset Message=Messages[ShowMessageNum]>
<!--- Custom script functions --->
<script type="text/javascript"
language="JavaScript">
// Because these variables is declared outside of a function block,
// they are maintained by JavaScript at the page level
var msMaxPerQuestion=<cfoutput>#MaxMillisecondsPerPage#</cfoutput>;
var intervalHandle;
var msMomentPageWasLoaded;
// Function to increment the msTimeElapsed variable
// and place its value in the TimeElapsed hidden field
function fillTimeElapsed() {
// Determine how many milliseconds have elapsed so far
msTimeElapsed=new Date().valueOf() - msMomentPageWasLoaded;
// Place the time elapsed (in milliseconds) in the hidden field
document.forms[0].TimeElapsed.value=msTimeElapsed;
// Display the timer value
var msg=((msMaxPerQuestion - msTimeElapsed) / 1000).toFixed(1);
document.getElementById("elSecsElapsed").inn218=msg;
// If the time has elapsed
if (msTimeElapsed >= msMaxPerQuestion) {
// Stop the timer
window.clearInterval(intervalHandle);
// Submit the form
document.forms[0].submit();
};
}
// This funciton executes when the page first loads
function initPage() {
// Records the current time (as number of milliseconds since 1/1/1970)
msMomentPageWasLoaded=new Date().valueOf();
// Start the timer
intervalHandle=window.setInterval('fillTimeElapsed()', 100);
// Set focus to the AnswerDate input field
document.forms[0].AnswerDate.focus();
};
</script>
<!--- Call the fillTimeElapsed() function once every 10 milliseconds --->
<body onload="initPage()">
<!--- Self-submitting form --->
<cfform action="#CurrentPage#?MessageNum=#ShowMessageNum#"
method="Post"
onsubmit="window.clearInterval(intervalHandle)">
<!--- Hidden field to pass secondsElapsed variable to ColdFusion --->
<cfinput type="Hidden"
name="TimeElapsed">
<!--- Ordinary form field --->
<p>
<strong><cfoutput>#Message#</cfoutput></strong>
<br>
<cfinput type="Text"
name="AnswerDate"
required="Yes"
validate="date"
message="Um, fill in the date first.">
<br>
<p>Think fast, you're being timed!<br>
(time remaining: <span id="elSecsElapsed"></span> seconds)<br>
<!--- Submit button --->
<p>
<cfinput type="Submit"
name="sbmt"
value="Submit Answer">
</cfform>
</cfif>
</body>
</html>
Opening Popup Windows
For better or for worse, one of the things that JavaScript is most used for most is to open popup windows. Much of the time, popup windows are an annoyance, but there are times when you may have a legitimate need to create one for your application. You can find a full discussion about popup windows in a JavaScript reference, but this section will quickly introduce you to the basics, emphasizing the fact that you can easily pass variables to ColdFusion as part of the popup-opening process.To open a popup window, use the window.open() method, in the following form:
The popupURL is the URL of the page to display in the popup window. The popupName is an optional target name for the popup window (if you provide the name of an existing window, the same window will be reused each time the method is called; if not, a new window is opened each time). The popupFeatures argument is an optional comma-separated list of window features, which you can use to control the size and position of the popup window. Table 17.16 lists most of the values you can supply in the popupFeatures string; consult a JavaScript reference for a complete listing.
window.open(popupURL, popupName, popupFeatures);
FEATURE | DESCRIPTION |
---|---|
width | The width of the popup window, in pixels. |
height | The height of the popup window, in pixels. |
top | The position of the window, in pixels, from the top of the screen. |
left | The position of the window from the left edge of the screen. |
resizable | Whether the window should be resizable (yes or no). |
scrollbars | Whether scrollbars should appear in the window (yes or no). Even when no, the scrollbars only appear when necessary. |
status | Whether the status bar should be displayed at the bottom of the popup window (yes or no). |
toolbar | Whether the browser toolbar (with the next and back buttons and so on) should appear at the top of the window (yes or no). |
menubar | Whether the usual browser menu bar should appear(yes or no). |
location | Whether the URL location (the area where you type a new location to browse to) should appear at the top of the window (yes or no). |
Of course, you are free to make the values of JavaScript variables available to the page you are displaying in the popup window. For instance, if you have a JavaScript variable called filmID, you can easily pass it as a URL parameter to the ShowFilm.cfm page, like so:
window.open("ShowFilm.cfm", "filmPopup", "width=300,height=200");
If you provide a name in the popupName argument, the popup window will be reused each time a new window.open() method executes that uses the same name. This can help avoid a situation where there are too many popup windows strewn about the user's screen. In such a case, it is often helpful to add an onload="window.focus()" attribute to the <body> tag of the window being opened, so that it moves in front of any other windows each time it is reused, like so:
window.open(
"ShowFilm.cfm?FilmID=" + escape(filmID),
"filmPopup",
"width=300,height=200");
The JSRelatedSelects4Popup.cfm page (included with this chapter's listings) provides a Show Film button that the user can use to display details about the selected film in a popup window, as shown in Figure 17.9. The detail page is provided by ShowFilm.cfm (also included with this chapter's listings), which includes the window.focus() line shown above so that the popup window for the film details always moves to the front as each film's details are loaded.
<BODY onload="window.focus()">