|
A Study in Flash Form Submissionby Colin Moock, author of ActionScript for Flash MX: The Definitive Guide, 2nd Edition and ActionScript for Flash MX Pocket Reference05/20/2003 |
In HTML, fill-in forms are a breeze to create: take one
<form> tag; add user-input tags to taste; bake at 350 degrees for one hour; serve and enjoy.
Historically, the creating forms in Flash hasn't been so simple. With the release of Flash MX's Flash UI components, things got a lot easier, but form submission is still trickier in Flash than it is in HTML. In HTML, forms can be submitted via a submit button or "automagically" via the Enter key. Flash does not have built-in support for Enter-key form submission, so we must handle the Enter key manually. The remainder of this article explains how to do just that. Download the source code for the following discussion here.
Flash forms are typically a collection of user interface components. To
"submit" a form to a server-side script or application, we must manually
assemble the value of each component into either a LoadVars or an XML
object, and then invoke that object's sendAndLoad() or
send() method.
|
Related Reading ActionScript for Flash MX: The Definitive Guide |
These steps are usually handled by a custom function or
method. Consider, for example, a simple login form with a user name text
field, a password text field, and a submit button. The text fields are
single-line input text fields with instance names of username_txt and
password_txt. The submit button is an FPushButton instance
named submit_pb. To handle form submission, we define a custom
submitForm() function. The code on our form's timeline looks
like this:
// Prepare the data transfer object. To keep
// things simple, we'll assume that the login
// results will be displayed as a web page in
// the browser rather than in Flash.
var sender = new LoadVars();
// Custom form-submission function.
function submitForm () {
// Assemble text field values into our LoadVars object.
sender.user = username_txt.text;
sender.pass = password_txt.text;
// Transfer the data to the server-side script.
sender.send("http://www.somesite.com/cgi-bin/login.pl", "_blank", "GET");
}
To make our submit button (submit_pb) invoke
submitForm() when pressed, we use the
FPushButton component's setClickHandler() method
as follows:
// This code must be on a frame in the same
// timeline as the earlier submitForm() function definition.
submit_pb.setClickHandler("submitForm");
Now for the tricky part: when the Enter key is pressed, we want to
invoke submitForm(), but only if one of the text fields in
the form is focused. To handle the Enter key, we'll add new custom methods
to the TextField class. First, let's rough out a new method
to check for Enter keystrokes. We'll call the method
onKeyDown() so that any TextField instance can
register to receive keystroke event notifications from the built-in Key
object.
TextField.prototype.onKeyDown = function () {
if (Key.getCode() == Key.ENTER) {
// Enter was pressed.
}
};
Our new method has a problem: if the user holds down the Enter key,
we'll get multiple keystroke events. We're only interested in the first
keystroke, so let's modify onKeyDown() to discard all but the
first press of the Enter key. We'll add a property,
pressedOnce, to track the first Enter key press, and we'll
add a new method, onKeyUp(), to clear the
pressedOnce property when the Enter key is released.
TextField.prototype.onKeyDown = function () {
if (Key.getCode() == Key.ENTER && this.pressedOnce == undefined) {
// Make a note that Enter was pressed so we don't bother
// handling it next time we get an onKeyDown event notification.
this.pressedOnce = true;
}
};
TextField.prototype.onKeyUp = function () {
// When the Enter key is released, reset the single-press detection property.
if (Key.getCode() == Key.ENTER) {
this.pressedOnce = undefined;
}
}
|
It's not enough to detect that the Enter key was pressed. We're only
interested in Enter keystrokes if a text field in the form is focused at
the time of the keystroke. Let's add another method to the
TextField class, isFocused(), which will tell us
whether a text field has input focus. In ActionScript, the
Selection object's getFocus() method returns the
current focus.
TextField.prototype.isFocused = function () {
// (The 'this' is the current text field instance.)
if (Selection.getFocus() == targetPath(this)) {
return true;
}
return false;
};
Note that the Selection.getFocus() method returns the path
to the currently focused object as a string, not as an object
reference. Hence, to compare the return of getFocus() to the
current text field, we must use either eval() to convert
getFocus()'s return to an object, or
targetPath() to retrieve the fully qualified path to the text
field. In our custom isFocused() method we use the
targetPath() approach.
Now that isFocused() is complete, let's adjust our
onKeyDown() method one last time so that it detects that the
Enter key was pressed and that the text field that detected the Enter
keystroke is currently focused. If both of those conditions are met, we'll
invoke a custom onSubmit() method directly on the text
field. The form developer is expected to provide the implementation for
onSubmit().
TextField.prototype.onKeyDown = function () {
if (Key.getCode() == Key.ENTER
&& this.pressedOnce == undefined
&& this.isFocused()) {
this.onSubmit();
this.pressedOnce = true;
}
};
TextField.prototype.onKeyUp = function () {
if (Key.getCode() == Key.ENTER) {
this.pressedOnce = undefined;
}
}
That takes care of our TextField additions. Our form's
text fields will now be able to respond to the Enter key. All that's left
to do is wire the text fields to the submitForm() function
and register them to receive Key events:
// Wire text field to submitForm().
username_txt.onSubmit = submitForm;
// Register text field to receive Key events.
Key.addListener(username_txt);
// Wire...
password_txt.onSubmit = submitForm;
// Register...
Key.addListener(password_txt);
That's it. Enter key presses in the user name and password text fields will now submit our form. Here's a look at the final code:
// ===============================================
// Augment TextField Class
// ===============================================
TextField.prototype.onKeyDown = function () {
if (Key.getCode() == Key.ENTER
&& this.pressedOnce == undefined
&& this.isFocused()) {
this.onSubmit();
this.pressedOnce = true;
}
};
TextField.prototype.onKeyUp = function () {
if (Key.getCode() == Key.ENTER) {
this.pressedOnce = undefined;
}
}
TextField.prototype.isFocused = function () {
if (Selection.getFocus() == targetPath(this)) {
return true;
}
return false;
};
// ===============================================
// Implement Form
// ===============================================
// Prepare the data transfer object.
var sender = new LoadVars();
// Activate Enter key for text fields.
username_txt.onSubmit = submitForm;
Key.addListener(username_txt);
password_txt.onSubmit = submitForm;
Key.addListener(password_txt);
// Set submit button handler.
submit_pb.setClickHandler("submitForm");
// Provide custom form submission function.
function submitForm () {
sender.user = username_txt.text;
sender.pass = password_txt.text;
sender.send("http://www.somesite.com/cgi-bin/login.pl", "_blank", "GET");
}
|
Related Reading
ActionScript for Flash MX Pocket Reference |
There are some related issues worth mentioning in passing.
This article concentrated on Enter-key submission from a text field,
but forms often include additional UI components such as listboxes and
radio buttons. To support the Enter key with those kinds of components,
you'll need to either add key and focus handling methods to them (much as
we did for TextField). You could also implement a centralized
key-handling strategy, where a single object detects keystrokes and then
loops through the components in the form to determine whether the form
should be submitted. At that level of complexity, it's probably worth
creating a custom Form class to manage your forms.
Form input should always be validated in Flash before it is submitted
to a server-side script or application. Like form submission, the
validation process should be packaged into a function or method. For
example, in our form we might have a validateForm() function
that returns true if the form data is valid, and false otherwise. We'd
then adjust our submitForm() function as follows:
function submitForm () {
if (validateForm()) {
sender.user = username_txt.text;
sender.pass = password_txt.text;
sender.send("http://www.somesite.com/cgi-bin/login.pl", "_blank", "GET");
} else {
// Provide feedback to user...
}
}
In a strict OOP language such as Java, our approach of adding custom
methods to the built-in TextField class wouldn't work. In
Java you can't just add arbitrary new methods to a built-in class on a
per-application basis. In our form we needed a specialized type of text
field, so it would have been best to subclass TextField and
add our custom methods to that subclass. Unfortunately, it's not possible
to subclass TextField directly in ActionScript because all
text field creation tools use the TextField class to generate
text fields. There's no way to instruct, say,
MovieClip.createTextField() to generate a new text field
instance from a custom class rather than from
TextField. Developers who are reluctant to add new methods to
built-in classes can avoid the issue by wrapping a text field in a
component and then adding the new methods to the component class rather
than to the TextField class.
Our form example used single-line input text fields. For information on handling the Enter key in multiline text fields, see moock.org's technote on the subject.
O'Reilly & Associates recently released (March 2003) ActionScript for Flash MX Pocket Reference.
Sample Excerpt, Variables, is available free online.
You can also look at the Table of Contents, the Index, and the Full Description of the book.
For more information, or to order the book, click here.
Copyright © 2009 O'Reilly Media, Inc.