This example demonstrates how to send a single text field variable from Flash to a Perl script, named echo.pl, and how to receive a response from echo.pl in Flash. The movie we'll build consists of an interface and two functions—initForm( ) and submitForm( ). The interface includes an input text field, a Submit button, and a movie clip that displays echo.pl's response. The initForm( ) function creates the server communication objects that send our variable between Flash and echo.pl. The submitForm( ) function formats the data and sends it to echo.pl. For simplicity, our code is attached to frame 1 of the scripts layer. In practice, you should attach the code to a frame following your preloader.
The example files are available at the online Code Depot.
HTML uses tags such as <SELECT>, <OPTION>, and <INPUT> to create a form's interface. In Flash, a form's interface can be built manually in the authoring tool (as in this example) or at runtime via ActionScript. Our form's text field and button are equivalent to HTML's <INPUT TYPE="TEXT">, <INPUT TYPE="TEXTAREA">, and <INPUT TYPE="SUBMIT"> tags.
|
Start building the interface by creating three layers: scripts, input form, and output.
Next, place a user-input text field on the input form layer, as follows:
Select the Text tool from the Tools panel.
On the input form layer, drag a rectangle big enough for a user to enter a single line of text.
Open the Property inspector (Window Properties).
In the Property inspector, for Text Type, select Input Text.
In the Property inspector, for Line Display, select Single Line.
In the Property inspector, for Instance Name, enter input_txt. (The _txt suffix activates code hinting in the Actions panel.)
In the Property inspector, select the Show Border Around Text button.
Alternatively, Flash MX users can create the input_txt text field at runtime with the MovieClip.createTextField( ) method, as follows:
// Create and place the text field on the main timeline. Parameters are: // instance name, depth, x position, y position, width, height _root.createTextField("input_txt", 1, 250, 235, 150, 20); // Make the field an input text field input_txt.type = "input"; // Set line display to single line input_txt.multiline = false; // Enable border and background input_txt.border = true; input_txt.background = true; // Optionally, set colors for the border and background input_txt.borderColor = 0x666666; input_txt.backgroundColor = 0x999999;
Next, add a Submit button to the input form layer as follows:
Choose Window Common Libraries Buttons.
From the Buttons.fla library's Push Buttons folder, drag an instance of the push button - blue button onto the Stage.
To make the Submit button call our custom function submitForm( ), which we'll build later, follow these steps:
Select the push button - blue button instance.
Choose Window Actions.
Enter the following code in the Actions panel:
on (release, keyPress "<Enter>") { submitForm( ); }
Flash MX allows us to achieve a similar result by assigning submitForm( ) as the callback function for the button's onRelease( ) handler. To do so, assign an instance name, such as submit_btn, to the button in the Property inspector. Then attach the following code to the main timeline (most suitably in initForm( )):
submit_btn.onRelease = submitForm;
In most cases, this syntax is preferable, because it keeps the code separated from the physical button on stage. However, we want our form to respond to the Enter key, so we use the Flash 5-style on(keyPress "<ENTER>") button handler, which provides an easy way to capture the Enter key. In more complex cases (for example, when handling multiple Submit buttons), we must resort to more advanced key handlers. See Key.addListener( ), Key.onKeyDown( ), and Key.onKeyUp( ) in the Language Reference for details.
To complete the form's front end, build a movie clip, named response, to display the results sent by echo.pl. The response clip has three states, represented by three keyframes labeled idle, loading, and doneLoading:
When the movie loads, response displays the idle frame (ordinarily invisible to the user), in which response waits for data to begin loading.
When variables are submitted, response displays the loading frame, indicating that data has been submitted to the server and that Flash is waiting for a reply.
When variables are received, response displays the doneLoading frame, in which the results are displayed to the user via a text field, output_txt.
To build response, first create a new movie clip symbol:
Choose Insert New Symbol, which opens the Create New Symbol dialog box.
In the Name box, enter responseClip.
For Behavior, choose Movie Clip.
Click OK.
Next, create an instance of responseClip:
From the Library, drag an instance of responseClip onto the main Stage's output layer.
Name the responseClip instance response.
Finally, create the labeled "state" frames in the responseClip symbol:
In the Library, double-click the responseClip symbol (this edits the clip).
Create four timeline layers named, from top to bottom, scripts, labels, loading, and outputField.
Create three keyframes on each layer in frames 1, 2, and 3.
On the labels layer, label keyframes 1, 2, and 3 as idle, loading, and doneLoading.
On the scripts layer, at frame 1, add the following code: stop( );.
On the loading layer, at frame 2, add the static text, "loading, please wait".
On the outputField layer, at frame 3, use the Text tool to draw a text box.
In the Property inspector, for Text Type, select Dynamic Text.
In the Property inspector, for Line Display, select Multiline.
In the Property inspector, for Instance Name, enter output_txt.
To send the value of input_txt to echo.pl, we'll create the custom functions initForm( ), shown in Example 17-1, and submitForm( ), shown in Example 17-2. The initForm( ) function creates one instance of the LoadVars class to send our data (dataSender) and another to receive echo.pl's response (dataReceiver). The initForm( ) function also assigns a callback function to dataReceiver's onLoad( ) handler, which executes when echo.pl's reply arrives. The callback function displays the reply in the response clip. Notice that initForm( ) creates a global variable used to refer to the form's timeline. Hence, all our references to the response clip are fully qualified.
/* * Function: initForm( ) * Desc: Creates LoadVars objects for sending and * receiving data to and from the server. * Parameters: None. */ function initForm ( ) { // Create a reference to the form timeline. _global.form_mc = this; // Create the LoadVars objects. // One to send... dataSender = new LoadVars( ); // ...and one to receive. dataReceiver = new LoadVars( ); // Assign a callback function to the dataReceiver's onLoad handler. // It will process the variables when they arrive. dataReceiver.onLoad = function ( ) { // Prepare the response clip for data display. form_mc.response.gotoAndStop("doneLoading"); // Display the value of output, the loaded variable, in the output_txt field. form_mc.response.output_txt.text = this.output; } }
The submitForm( ) function, shown in Example 17-2, gathers the data and transmits it to echo.pl.
/* * Function: submitForm( ) * Desc: Retrieves user input and sends it to the server. * Parameters: None. */ function submitForm ( ) { // Assign the value of input_txt to a property of dataSender. The escape( ) // function encodes the & character to avoid network transfer errors. dataSender.formInput = escape(input_txt.text); // Display a loading message in the response clip. form_mc.response.gotoAndStop("loading"); // Display what we're sending in the Output window, for debugging purposes. trace("Sending " + dataSender.toString( )); // Send the properties of dataSender to the server, and wait for a reply. dataSender.sendAndLoad("http://www.yourserver.com/cgi-bin/echo.pl", dataReceiver, "GET"); }
The formInput property of the dataSender object contains the data to be transmitted—the current input of the input_txt text field, escaped (encoded) for safe network transfer:
dataSender.formInput = escape(input_txt.text);
While the user waits for echo.pl to respond to our form submission, the code displays a loading message in the response clip:
form_mc.response.gotoAndStop("loading");
For testing purposes, we display the data to be sent in the Output window, using the toString( ) method:
trace("Sending " + dataSender.toString( ));
Finally, we submit the form using sendAndLoad( ), instead of send( ) or load( ), because we're both sending variables to, and receiving variables from, echo.pl. The sendAndLoad( ) method sends formInput (and any other dataSender properties) to echo.pl:
dataSender.sendAndLoad("http://www.yourserver.com/cgi-bin/echo.pl", dataReceiver, "GET");
The sendAndLoad( ) method takes three parameters: url (the location of the server script), targetObject (the LoadVars object that should receive the results), and method (the HTTP method, either "GET" or "POST"). When sendAndLoad( ) executes, dataSender's properties are converted to a single ampersand-delimited string of variable name/value pairs and sent to echo.pl.
When the user clicks the Submit button in our form, Flash initiates an HTTP GET request that executes the Perl script echo.pl. For our form to work, echo.pl must be placed in a CGI-enabled directory of a web server and configured by the server's administrator as follows:
The script must be executable (typically, this means setting the script file's permissions to 755).
On Unix, the path to the Perl interpreter must be set in the script.
Example 17-3 shows the source code for echo.pl. Note that in Perl, the # character indicates a comment.
#! /usr/local/bin/perl #------------------------------------------------------------------------------- # Name: Simple Flash Echo # Version: 1.2.1 # Author: Derek Clayton derek@moock.org # Description: Echoes back name/value pairs received from a Flash GET or POST. #------------------------------------------------------------------------------- # MAIN #------------------------------------------------------------------------------- use CGI; # Use the CGI.pm for easy parsing $query = new CGI; # Query object $echoString = "output="; # Initialize our output string &getInput; # Get the input received from Flash &writeResponse; # Write the response back to Flash exit; # Exit the script #------------------------------------------------------------------------------- sub getInput { # For each key get the associated value and add to the echo string foreach $key ($query->param) { $value = $query->param($key); $echoString .= "$key:$value\n"; } # Remove the trailing newline (\n) before writing response chomp($echoString); } sub writeResponse { # Set content type for Flash print $query->header({"Content-Type"=>"application/x-www-form-urlencoded"}); # Write the output print $echoString; }
The echo.pl script simply returns a single variable, output, that contains a single string representing all the variables we sent to the server. Here are the specific tasks echo.pl performs.
It accepts data sent by Flash and parses that data into a series of variable names and values. For example, it converts our dataSender.formInput property to the variable formInput. Any other properties attached to dataSender would likewise be converted to variables.
It assembles those variable names and values into a single string (to return to Flash) of the form:
output=name1:value1\nname2:value2\n...namen:valuen
For example, in response to our form submission, echo.pl creates the string:
output=formInput:theInputValue
If we give dataSender another property, country, with a value of "Canada", then echo.pl creates the string:
output=formInput:theInputValue\ncountry:Canada
It returns the string to Flash.
When Flash receives the string from echo.pl, it finds the output variable and automatically adds a corresponding output property on dataReceiver. The value of the output property is the string containing the list of variables we sent to echo.pl.
Obviously, echo.pl is merely a proof of concept. When applied, however, the concept can have interesting and powerful results. For an example of a more fully developed Perl system, see the flat file database sample available under "Server Communication" at the online Code Depot.
Recall that when we sent the properties of dataSender to echo.pl, we requested that echo.pl's return value be stored in the dataReceiver object:
dataSender.sendAndLoad("http://www.yourserver.com/cgi-bin/echo.pl", dataReceiver, "GET");
When data is received from echo.pl, Flash executes the callback assigned to dataReceiver.onLoad( ). We originally assigned that callback inside our initForm( ) function in Example 17-1; let's take a closer look at it now:
dataReceiver.onLoad = function ( ) { // Prepare the response clip for data display. form_mc.response.gotoAndStop("doneLoading"); // Display the value of output, the loaded variable, in the output_txt field. form_mc.response.output_txt.text = this.output; }
This function moves response's playhead to the doneLoading frame, where the text field output_txt resides. Then, it displays the value of output (supplied by echo.pl) in the response clip's output_txt text field. Note that the callback is executed as a method of dataReceiver, so the dataReceiver object is referred to as this inside the function.
All that's left to do is try the form out! Export your movie, enter some text in the input text field, and click the Submit button. If you entered "test" you should see "formInput:test" appear in the output_txt text field. If the form doesn't work the first time, make sure your server script is configured properly. And remember, you can study the functional version posted at the online Code Depot.
Reader Exercise: Add a Reset button that clears the value of the form's input field. Simply create a new button in the formClip and attach the following code to it:
on (release) { input_txt.text = ""; }
Also, try adding more than one input field to your form; the Perl script will faithfully return as many variables as you send it, assigned as a group to the variable output. Can you split them up, using the String class's methods, and display each variable's value separately?