Lesson 15. Using Formatters and Validators

Flex provides many types of built-in formatters and validators that enable you to display and validate user-supplied data such as dates, numbers, and currencies. Using the built-in data validators on the client side, you can make your application perform better by reducing calls to the server for validation. You can also save development time by using the built-in formatters to automate the often repetitive process of formatting data.

image

Validating customer information

Introducing Formatters and Validators

Flex formatters convert raw data into a customized string using predefined rules. The formatters can be used in MXML or in ActionScript and work well with data binding to simplify the display of formatted data.

Validators are used to ensure that data meets specific criteria before the application attempts to use it. This can be particularly important if you expect a user to input a number for a mathematical operation or a date for scheduling. Like formatters, validators can be used in MXML or ActionScript. They provide logical feedback on data input (valid or invalid) but also provide visual feedback in the way of red borders and error messages when input is invalid.

Formatters

A formatter is simply an ActionScript class that descends from (is a subclass of) the Formatter class. Some of the formatters available include:

• mx.formatters.CurrencyFormatter

• mx.formatters.DateFormatter

• mx.formatters.NumberFormatter

• mx.formatters.PhoneFormatter

• mx.formatters.ZipCodeFormatter

Formatters manage quite a bit of complexity for you, but they are exceedingly simple to use. Here is a CurrencyFormatter defined in MXML:

<mx:CurrencyFormatter id="myFormatter"
   precision="2"/>

This formatter can be applied either in ActionScript or in MXML with data binding, using the following syntax:

trace( myFormatter.format( 123 ) );
//outputs $123.00 in the United States

<s:Label text="{ myFormatter.format( someData ) }"/>

In the latter example, each time someData changes, the format() method will be called and the output displayed in the label.

Previously, you accomplished something similar using concatenation of strings. You wrote code like this:

<s:Label text="Your Cart Total: ${shoppingCart.total}"/>

This strategy has several problems. First, it becomes complicated to control variables defining how the user wants to see this currency presented. For example, if you are creating a globalized application, you will need to support different currency symbols, different regional uses of commas and periods, and varying degrees of precision. Second, this code assumes that the currency symbol will always appear before the number. This is certainly not the case in many countries. By using Flex formatters, these and other issues are handled for you.

Validators

Flex also has a set of Validator classes that you can use to check whether a data type is valid (for example, if the input is a number) and to ensure that the input has been formatted correctly (for example, if a date is entered in a specific format). As with Formatter classes, you can use Validator classes either as MXML tags or instantiate them in ActionScript.

Using validators, you can perform a large amount of data validation in the client application, instead of waiting until data is submitted to the server. Not only does this provide a more responsive user experience, it also reduces the number of calls between the client and the server. This yields a better-performing application. Client-side validation is not a perfect solution; some types of data validation (such as security issues) are still best performed at the server. But using Validator classes at the client reduces server calls to only these use cases.

All Flex validators are a subclass of the Validator class. Some of the validators available as part of the Flex framework include:

• CreditCardValidator

• DateValidator

• EmailValidator

• NumberValidator

• PhoneNumberValidator

• SocialSecurityValidator

• StringValidator

• ZipCodeValidator

Much like the Formatter classes, the Validator classes cover a large number of use cases and conditions that you might not consider on your own. By using the Flex validators, you are better prepared for robust applications and internationalization requirements.

Using Formatter Classes

In this exercise, you will apply a CurrencyFormatter class so all the price selections are displayed as local currency in the FlexGrocer application. There are multiple places in which prices are displayed in the application, including:

• The list of grocery products displayed

• The total of the shopping cart

• The subtotal and list prices in the user’s shopping cart

• The checkout process

The CurrencyFormatter adjusts the decimal rounding and precision and sets the thousands separator and the negative sign. You can specify the type and placement of the currency symbol used, which can contain multiple characters, including blank spaces.

  1. Open ShoppingView.mxml from your views package.

    Alternatively, if you didn’t complete the previous lesson or your code is not functioning properly, you can import the FlexGrocer.fxp project from the Lesson15/start folder. Please refer to Appendix A for complete instructions on importing a project should you ever skip a lesson or if you ever have a code issue you cannot resolve.

  2. Within the <fx:Declarations> tags, add an <mx:CurrencyFormatter> tag. Assign the tag an id of currency and specify a precision of 2:

    image

    The decimal rounding, thousands separator, currency symbol, and the negative sign are properties that can be set on the CurrencyFormatter; we have left these at their defaults. You specified a precision of 2, meaning that two decimal places will always be displayed.

    The CurrencyFormatter receives its default settings from user locale information. This locale information exists inside resource bundles that you can create for various locales; however, doing so is beyond the scope of this book.

    Note

    image

    If you would like to learn more about resource bundles or the process of internationalizing an application, refer to “Creating Resources” in the Adobe Flex 4 help documentation.

  3. Locate the Label control that displays the words Your Cart Total along with a dollar sign and the shopping cart’s total. Inside the data binding for the text property, replace the dollar sign and binding expression with a call to the format() method of the currency object, and pass shoppingCart.total to the method, as follows:

    <s:Label text="Your Cart Total: {currency.format(shoppingCart.total)}"/>

    The format() method takes the value and applies all the parameters you set on the <mx:CurrencyFormatter> tag. In this case, you are using the default currency symbol (a dollar sign for the en_US locale where this book was written) and specifying the precision, so two digits to the right of the decimal separator will always be maintained.

  4. Next locate the renderProductName() method.

    Presently, this method returns a string created by concatenation parentheses around the item quantity along with the product name, a dollar sign, and the item subtotal.

  5. Remove the $ from the string and pass the item.subtotal to the currency.format() method before using it in the concatenation:

    image

  6. Save the ShoppingView class and run the FlexGrocer application.

    image

    Add a few items to the cart and you will quickly see the currency formatter is now adding precision and limiting the number of decimal places to 2. Several other places in the application could use a CurrencyFormatter. You will handle those next.

  7. Open CartGrid.mxml from the components package.
  8. Within the <fx:Declarations> tags, add an <mx:CurrencyFormatter> tag. Assign the tag an id of currency and specify a precision of 2:

    image

  9. Locate the function named renderPriceLabel(). Change the return statement of the function to use the format() method of the currency instance.

    image

    Previously, you had to cast the subtotal as a String before concatenating with the $. This isn’t necessary when using formatters. The format() method accepts an Object and internally converts it as needed.

  10. Open Review.mxml from the views/checkout package.
  11. Within the <fx:Declarations> tags, add an <mx:CurrencyFormatter> tag. Assign the tag an id of currency and specify a precision of 2.
  12. Still inside the <fx:Declarations> tags, add an <mx:DateFormatter> tag. Assign the tag an id of df:

    image

  13. Find the Label instance inside the Delivery Date form item. Pass the orderInfo.deliveryData to the format() method of the df instance before assigning it to the text.

    <s:Label text="{df.format(orderInfo.deliveryDate)}"/>

    Like the CurrencyFormatter, the DateFormatter has a format method used to convert data into a String. In this case, you are using the default format specified by the user’s locale.

  14. Find the Label instance that displays the user’s total. Pass the shopppingCart.total to the format() method of the currency instance before concatenating it and assigning it to the text:

    <s:Label text="Total {currency.format(shoppingCart.total)}"/>

  15. Save this file.
  16. Open ProductItem.mxml from the components package.
  17. Within the <fx:Declarations> tags, add an <mx:CurrencyFormatter> tag. Assign the tag an id of currency and specify a precision of 2.
  18. Find the Label instance that displays the products listPrice. Pass the product.listPrice to the format() method of the currency instance before assigning it to the text.

    <s:Label text="{currency.format(product.listPrice)}" id="price"/>

  19. Save this file and run the application. If you proceed through checkout, you should see formatted currencies and dates throughout.

Examining Two-Way Bindings

In Lesson 8, “Using Data Binding and Collections,” you learned about data binding, which updates the view components when data changes. Flex 4 introduces a second type of data binding called two-way binding. Two-way binding is most effective when combined with user input forms.

In this type of data binding, view components are updated when data changes; however, the data is also updated when the component changes. You can think of regular data binding as moving in one direction: when the data changes, the view changes. You can think two-way binding as bidirectional: if either changes, the other updates.

In practice, two-way binding is extremely easy to use. There is simply a syntax difference when declaring a control as bound to data.

To bind a TextInput to a piece of data using traditional data binding, your code would look like this:

<s:TextInput text="{someData}"/>

To use two-way binding, you simply prepend the expression with an @ symbol.

<s:TextInput text="@{someData}"/>

Now, if you were to change the someData variable, the TextInput would update. Additionally, if you were to type into the TextInput, the someData variable would be updated.

  1. Open CustomerInfo.mxml from your views/checkout package.
  2. Note that the orderInfo object in the <fx:Script> block is of type OrderInfo and is marked Bindable.
  3. Find the TextInput inside the Customer Name form item and examine the declaration:

    <s:TextInput text="@{orderInfo.billingName}"/>

This means that this field will display the information in the billingName property of the orderInfo object. Further, the billingName property and the entire orderInfo object will be monitored for changes. If either changes, this field will be updated with the new value. If the user changes the value in this TextInput by typing a new value or deleting what is already there, the billingName property will be updated to reflect the contents of the field.

Two-way binding does have one limitation at this time: the types of both the source and destination must be the same. With traditional data binding, you can bind a variable declared as a Number to the text input of a Label, even though that Label is expecting a String instance. Traditional data binding will attempt to convert the Number to a String on your behalf. Two-way data binding cannot work unless both the source and destination are the same.

Using Validator Classes

In this exercise, you will use a ZipCodeValidator class to check whether a postal code is a valid U.S. zip code or Canadian postal code along with a StringValidator to ensure that the billing name is at least two characters long during the checkout process.

  1. Open CustomerInfo.mxml from your views/checkout package.
  2. Find the FormItem with the label Customer Name and set the required attribute of that FormItem to true.

    <mx:FormItem label="Customer Name" required="true">

    Setting the required attribute of a FormItem tag causes Flex to place a red asterisk next to the form field when it is displayed. This is purely a visual property. By itself it does nothing to ensure the user enters data into this field.

  3. Inside the FormItem, set the id property of the TextInput to billingName.

    <mx:FormItem label="Customer Name" required="true">
       <s:TextInput id="billingName" text="@{orderInfo.billingName}"/>
    </mx:FormItem>

    Shortly, you will need to refer to this TextInput by the id to validate its input.

  4. Find the FormItem with the label Zip and set the required attribute of that FormItem to true:

    <mx:FormItem label="Zip" required="true">

    Remember, this is purely a visual detail.

  5. Inside the FormItem, set the id property of the TextInput to billingZip.

    <mx:FormItem label="Zip" required="true">
       <s:TextInput id="billingZip" text="@{orderInfo.billingZip}"/>
    </mx:FormItem>

  6. Inside the <fx:Declaration> tag pair, add an <mx:ZipCodeValidator> tag. Bind the source property of the ZipCodeValidator to the billingZip TextInput. Still in the ZipCodeValdator, specify the property attribute as text and specify the required attribute to true.

    <mx:ZipCodeValidator source="{billingZip}"
      property="text"
      required="true"/>

    The <mx:ZipCodeValidator> validates that a string has the correct length for a five-digit zip code, a five-digit + four-digit U.S. zip code, or a Canadian postal code. The source attribute indicates the control containing the data to be validated. As you will see, this also specifies where any error messages will appear. The property attribute indicates which property of the control you wish to validate. In this case you are indicating that the text property of the billingZip contains the data for validation. Finally, the required attribute indicates that this field must be supplied. If required was set to false, a blank field would be acceptable, but if the user entered any information, it must conform to a valid zip code.

  7. Still inside the <fx:Declaration> tag pair, add an <mx:StringValidator> tag. Bind the source property of the StringValidator to the billingName TextInput. Specify the property attribute as text, the required attribute as true, and minLength as 2.

    <mx:StringValidator source="{billingName}"
      property="text"
      required="true"
      minLength="2"/>

    The <mx:StringValidator> validates that a string falls within certain size parameters. Here you are indicating that the String must be at least a length of 2 to be valid.

  8. Save and compile the application.

    Click the Checkout button; enter some letters for the zip code in the billing information screen. When you exit the field, you should see a red highlight around the text field; when you move the pointer over the text field, you will see the default error message appear.

    However, even if you leave these fields in error, you can still click the Proceed button to move on to the next screen. You will correct that next.

  9. Return to CustomerInfo.mxml.

    You will now add code to prevent leaving this page until the user corrects any errors.

  10. Inside the <fx:Declarations> tag pair, wrap the two validators you created above in an <fx:Array> tag with the id of validators.

    image

    This code creates an array named validators. It inserts the two validator instances created into that array so that they can be referred to as a group.

  11. Find the handleProceed() method.

    This method is called when the user clicks the Proceed button. It dispatches an event, which changes to the next view in the ViewStack.

  12. Add a new local variable named errors of type Array on the first line of this method. Assign it to the result of calling the Validator.validateAll() method, passing it the validators array you just created.

    var errors:Array = Validator.validateAll( validators );

    If you used code completion, mx.validators.Validator will be imported for you. If not, import it now. The validateAll() method is a static method of the Validator class. It is a utility method that accepts an array of validators, like the one you created in step 10. It runs each validator and aggregates any failures, meaning that this array will contain any validation errors found as a result of running each of your validators. If the array is empty, there were no validation errors.

  13. Just below the errors array declaration, create an if-else statement that checks if the length property of the errors array is greater than 0.

    if ( errors.length > 0 ) {
    } else {
    }

    Effectively, this if statement checks if there were any validation errors.

  14. Move the code that dispatches the proceed event inside the else block.

    if ( errors.length > 0 ) {
    } else {
       dispatchEvent( new Event( 'proceed' ) );
    }

    If there are no errors, the user will be allowed to continue.

  15. If there were errors, call the static show() method of the Alert class and pass it the string Please fill in all required fields. Here is the final function.

    private function handleProceed( event:Event ):void {
       var errors:Array = Validator.validateAll( validators );

       if ( errors.length > 0 ) {
          Alert.show( "Please fill in all required fields" );
       } else {
          dispatchEvent( new Event( 'proceed' ) );
       }
    }

    The Alert class is a handy way to notify the user of an error or problem with the application.

  16. Save and run the application. Enter invalid data in the Zip field and attempt to proceed to the next page.

    image

You now have a form capable of collecting valid data, informing the user when that data is invalid, and preventing the user from proceeding if they have not yet corrected the invalid data.

What You Have Learned

In this lesson, you have:

• Learned how to apply a formatter to incoming text (pages 368–377)

• Learned about two-way data binding (pages 371372)

• Learned how to apply a validator to outgoing data (pages 372376)

• Learned to trigger validation from ActionScript (pages 374375)

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset