Tuesday, August 11, 2009

Tour de Flex and Flex Component Explorer

If you haven't already seen this awesome Flex website then check it out.

Tour de Flex


It has examples (including source code) of all the common Flex 3 components (DataGrid, Tree, Button, Canvas, etc) as well as a TON of other examples (269 at the last count) from various open source projects including Flex Yahoo Maps, advanced Data Visualizations (3D charts, gantt charts, calendar views, etc), Cloud APIs (searching Amazon, eBay, Flickr, etc) and much more.

There is also the original Adobe Flex 3 Component Explorer which contains examples of just the core Flex 3 components.

For examples on styling components check out the Flex 3 Style Explorer site. I also find this list of all the styles for each Flex component useful: Flex 3.0 CSS Properties List.

Friday, August 7, 2009

Counting Words, StringWordValidator

I was recently required to limit the number of words in a TextArea. It's easy to limit the number of characters by using the TextArea.maxChars property, but how do you restrict the number of words?

The way I solved this problem was to make a new class that extends mx.validators.StringValidator and adds the following properties:
  • maxWords - the maximum number of words allowed
  • minWords - the minimum number of words allowed
  • tooManyWordsError - the error string to be displayed when too many words are entered
  • tooFewWordsError - the error string when not enough words are entered
  • trim - trims the input string before the validation occurs

Here is the utility function I wrote for counting how many words are in a string:
    /**
     * Splits the text into words and returns the number of words found.
     * If the text is null or blank (trimmed) then 0 is returned.
     * The regular expression used is /\s+/g which splits the text into
     * words based on whitespace.
     */
    public static function countWords(txt:String):uint {
        var count:uint = 0;
        if (txt != null) {
            txt = StringUtil.trim(txt);
            if (txt.length > 0) {
                count = txt.split(/\s+/g).length;
            }
        }
        return count;
    }

And here is it in action (view source). The validator will run when the TextArea loses focus (that is the default behavior), so try typing in one word and then pressing tab. You can also adjust the minimum and maximum number of words allowed and the validation will be updated immediately.

  • StringWordValidator source
  • ErrorTipManager source (see previous blog post on Always showing error tips)

  • I also included the ResizableTextArea class too just for fun.

    Thursday, August 6, 2009

    Always showing error tips (validators)


    Many people have complained about how Flex 3's error validation messages are not shown unless you hover your mouse over the input field that is invalid. See the image on the right and you'll probably know what I'm talking about. If not, then when you use a mx.validators.Validator on an input field such as a TextInput or TextArea and the user enters invalid data then the input control gets a red border indicating an error. But the error message (e.g. "This field is required") is ONLY displayed when the user hovers the mouse over the input field.

    After reading a few other posts on the subject, including a bug report that is in the Adobe Bug Tracker I decided to see if I could come up with a nice easy solution.

    I made a new class called ErrorTipManager that has a bunch of public static functions that lets you easily attach your validators (or your own validation functions). The code is documented, so view the sample below and right click view source to get the source code. The error tips should stay in the correct position even when the input moves (from a window resize or layout).



    A lot of credit goes to Aral Balkin's blog entry on Better form validation in Flex. I also got help from this blog on how to show error tooltips.

    Note that if you use the ErrorTipManager as described above and you set the validator.enabled = false; then the error tip will still be displayed. The validator does not fire an event when the enabled value changes, so it isn't possible to automatically update the visibility of the error tip. Instead you can do it manually by calling ErrorTipManager.hideErrorTip(validator.source, true). See the source code of the example above - I've added in a CheckBox that controls the second validator's enabled state.

    August 26th, 2009 update
    Fixed a problem where the error tip wasn't being position properly.

    November 2nd, 2009 update
    Added two new functions to ErrorTipManager for handling error tips in popup windows:
    • registerValidatorOnPopUp(validator, popUp, hideExistingErrorTips) - registers the validator and adds move and resize listeners on the popUp. It can also hide any existing error tips (this is a good idea because the existing error tips appear on top of the popUp window which doesn't look good).
    • unregisterPopUpValidators(popUp, validateExistingErrorTips) - unregisters all the validators associated with the popUp and removes the move and resize listeners that were added to the popUp. It can also validate all the remaining validators which will cause the error tips to re-appear now that the popUp has closed.

    March 24th, 2010 update
    Fixed a problem where the error tip wasn't being positioned properly when the parent container was scrolled. It will also hide the error tip if the source component gets scrolled out of the view. I also now move the error tip in front of other error tips when it gets positioned.

    July 14th, 2010 update
    Added two more event listeners in the ErrorTipManager to listen for when the input is hidden (visible="false") and when it gets removed from its parent (input.parent.removeChild(input)).
    This still does not solve the problem where the error tip remains visible when the parent is hidden or removed (e.g. if the input is inside a TabNavigator and the tab changes). In this case I'd suggest manually hiding or removing the error tip. Listen for the appropriate event like "change" and then call ErrorTipManager.hideErrorTip(input).

    March 2011 update
    I've posted an alternate approach to displaying validation error messages that doesn't involve the rather hacky approach above. You can view the blog post here.