Building an Address Book > Creating the Application Functions > The enterEditMode() Function

 

The enterEditMode() Function

The enterEditMode() function is one of the three "application state management" functions in the addresss book. The address book operates in two simple modes:

Browse mode, in which users can view the list of contacts and use the buttons in the address book pane.

Edit mode, in which users modify the content of a specific contact via the "contact details" pane.

While in one mode, the tools in the non-active pane are disabled. Our "application state" functions do the work of switching between modes.

The enterEditMode() function switches the application into edit mode. It is invoked when the Add Contact or Update Contact button is pressed.

To switch to edit mode, the enterEditMode() function performs the following tasks:

Enables the "contact details" pane text fields.

Places the cursor in the First Name text field (in other words, "focuses" First Name).

Enables the phone type ComboBox.

Disables the "address book" pane.

Creates "Done" and "Cancel" PushButton components.

The complete listing for enterEditMode() is shown below. By now we've seen many of the techniques in the code. Read through the listing, then we'll examine some of the features new to this function.

/*
 * Function: enterEditMode()
 *   Desc: Enables the editing in the contact details pane while
 *         disabling the address book pane. Registered as the 
 *         click handler for the add and edit buttons.
 *   Parameters:
 *     component    A reference to the pushButton component that
 *                  requested edit mode. Either the "add" or "edit" button.
 */

function enterEditMode (component) 
{
  // Check which button called the function. If it was the 
  // Edit button, then edit mode's "Done" button should 
  // call doUpdateContact. If it was it was the Add button,
  // Then edit mode's "Done" button should call doAddContact.
  var doneAction;
  if (component == editButton_pb) {
    doneAction = "doUpdateContact";
    
    // Before we go any further, we need to be sure something
    // is actually selected in the listbox.
    if (contactListBox_lb.getSelectedIndex() == undefined) {
      // Nothing's selected, so abort the edit attempt.
      return;
    }

  } else if (component == addButton_pb) {
    doneAction = "doAddContact";
    // Clear the text fields...
    firstNameField.text = "";
    lastNameField.text = "";
    emailField.text = "";
    phoneField.text = "";
    companyField.text = "";
    commentsField.text = "";
    addedField.text = "";
    modifiedField.text = "";    
  }

  // Turn text fields on.
  for (var i = 0; i < editFields.length; i++) {
    // Make text fields editable.
    editFields[i].type = "input";
    editFields[i].selectable = true;

    // Highlight the text fields.
    editFields[i].backgroundColor = 0x322E5A;
    editFields[i].borderColor = 0x9999FF;
    editFields[i].background = true;
    editFields[i].border = true;
  }

  // Focus the firstName text field
  Selection.setFocus(firstNameField);

  // Allow the user to use the phone combo box.
  phoneComboBox_cb.setEnabled(true);
  // Set the phone combo box to the first item
  // if we're adding a contact.
  if (component == addButton_pb) {
    phoneComboBox_cb.setSelectedIndex(0);
  }

  // Disable the address book interface
  addButton_pb.setEnabled(false);
  removeButton_pb.setEnabled(false);
  editButton_pb.setEnabled(false);
  sortAZButton_pb.setEnabled(false);
  sortZAButton_pb.setEnabled(false);
  contactListBox_lb.setEnabled(false);

  // Make "save changes" button
  this.attachMovie("FPushButtonSymbol", "doneButton_pb", 50);
  doneButton_pb.setClickHandler(doneAction);
  doneButton_pb.setLabel("Done");
  doneButton_pb._x = 558;
  doneButton_pb._y = 446;

  // Make "abort edit" button
  this.attachMovie("FPushButtonSymbol", "cancelButton_pb", 51);
  cancelButton_pb.setClickHandler("cancelEditMode");
  cancelButton_pb.setLabel("Cancel");
  cancelButton_pb._x = 668;
  cancelButton_pb._y = 446;
}

As in the sortListBox() function, the enterEditMode() function uses the component parameter to determine the button that triggered it. The button reference tells us whether the user is adding a new contact or just editing an existing one:

  if (component == editButton_pb) {
    // user is editing
  } else if (component == addButton_pb) {
    // user is adding
  }

When the user is adding a contact, we clear the text fields by setting their text property to the empty string (""). When the user is editing a contact, we must be sure there's a selected item to edit. If there's nothing selected in contactListBox_lb, we abort the attempt to enter edit mode. We use the getSelectedIndex() method to check the current selection in contactListBox_lb; when getSelectedIndex() returns undefined, we know no item is selected.

  
  if (contactListBox_lb.getSelectedIndex() == undefined) {
    // Nothing's selected, so abort the edit attempt.
    return;
  }

After the initial decision to add or edit is made, we enable the "contact details" pane text fields. Recall that in init() we stored references to our movie's TextField objects in an array called editFields. We can now use that array to process the text fields as a group, making each text field editable by setting its type to "input". We must also ensure that the text in each field can be selected by setting the selectable property to true as follows:

 
  for (var i = 0; i < editFields.length; i++) {
    // Make text fields editable.
    editFields[i].type = "input";
    // Make text fields selectable.
    editFields[i].selectable = true;
    ...

While we're at it, we turn each field's background and border on, and assign it a color:

    ...
    editFields[i].backgroundColor = 0x322E5A;
    editFields[i].borderColor = 0x9999FF;
    editFields[i].background = true;
    editFields[i].border = true;
  }

This gives a nice active effect to the "contact details" pane with very little effort!

After focusing the First Name text field and disabling the "address book" pane, we dynamically add a "Done" and a "Cancel" PushButton to the "contact details" pane. So far, all the components of our movie have been manually placed in the Macromedia Flash MX authoring tool. However, it is perfectly normal to create components through ActionScript. The Flash UI Components are just complex movie clips that can be added to a movie with the MovieClip.attachMovie() method.

To create a new "Done" PushButton, we use attachMovie() as follows:

this.attachMovie("FPushButtonSymbol", "doneButton_pb", 50);

The parameters of attachMovie() indicate the following: the linkage id of the component in the library ("FPushButtonSymbol"); the instance name of the component ("doneButton_pb"); and the depth at which the component should be placed (50).

Of course, when we attach a component with ActionScript, we cannot use the Property inspector to customize the component's parameters. Instead, we use methods of the components to set parameters. For example:

  // Set the text displayed on the button.
  doneButton_pb.setLabel("Done");

We also set the callback functions for the Done and Cancel buttons through a method: setClickHandler(). In the case of the Done button, the handler is assigned either "doAddContact" or "doUpdateContact", depending on whether the user is adding or editing a record. The doAddContact() and doUpdateContact() functions save the user's data to our SharedObject.

  // The variable doneAction contains a
  // string, either "doUpdateContact" or
  // "doAddContact".
  doneButton_pb.setClickHandler(doneAction);

We set the Cancel button callback function to cancelEditMode() with a string literal:

  cancelButton_pb.setClickHandler("cancelEditMode");

Finally, because a component is a movie clip, it may be positioned on stage with the _x and _y movie clip properties:

  // Position the new button
  doneButton_pb._x = 558;
  doneButton_pb._y = 446;

The "Done" PushButton is now in place. We add the "Cancel" PushButton in the exact same way. Note, however, that we assign its click handler using a string literal rather than a variable because we always want the Cancel button to invoke the same callback, cancelEditMode(), when pressed.