Web DevCenter    
 Published on Web DevCenter (http://www.oreillynet.com/javascript/)
 See this if you're having trouble printing code examples


ActionScript for Flash MX: The Definitive Guide, 2nd Edition

A Study in Flash Form Submission

by Colin Moock, author of ActionScript for Flash MX: The Definitive Guide, 2nd Edition and ActionScript for Flash MX Pocket Reference
05/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.

ActionScript for Flash MX: The Definitive Guide

Related Reading

ActionScript for Flash MX: The Definitive Guide
By Colin Moock

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
Quick Reference for Flash MX Programmers
By Colin Moock

Further Considerations

There are some related issues worth mentioning in passing.

Handling Enter for Other Components

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.

Validation

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...
  }
}

Good OOP Form

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.

Multiline Text Fields

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.

Copyright © 2009 O'Reilly Media, Inc.