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.

60 comments:

  1. Great example, congratulations.

    Help me so much!

    Thanks,

    Silva Developer

    ReplyDelete
  2. Great work. I did have a problem validating a TextInput control in a modal dialog. The code can't seem to place the error tip in the correct place. From what I can tell, it looks as though the coordinates are that of the parent container, not the modal container.

    Cheers!
    AllynTech

    ReplyDelete
  3. Great solution -- I have the same problem of the tooltip location is outside the parent form. Any ideas?

    ReplyDelete
  4. The implementation of the method getErrorTipPosition isn't quite correctly defined.

    Here's what it should be.

    private static function getErrorTipPosition(target:DisplayObject):Point {
    // position the error tip to be in the exact same position as the real error tooltip
    var pt:Point = new Point();
    if (target) {
    // need to get the position of the target in global coordinates
    //var globalPos:Point = target.localToGlobal(new Point(target.x, target.y)); Not correct (PG).
    var globalPos:Point = target.localToGlobal(new Point(target.width, target.y)); //Use the target.width instead (PG).
    // position to the right of the target
    //pt.x = globalPos.x + target.width + 4; ///Not correct (PG).
    pt.x = globalPos.x + 8;// No need to add the target.width, increase the offset (PG).
    pt.y = globalPos.y - 2;
    }
    return pt;
    }

    Patrick Groves

    ReplyDelete
  5. Thanks for your comments, I've now updated the example above to work properly in (hopefully) all situations, including in a popUp dialog.
    Chris

    ReplyDelete
  6. Great work, nice and clean solution!
    Still have a small problem getting it to look perfect though.
    The error text is displayed in a red tooltip area that is 30-40% to wide.
    ("balloon" width is 130-140% of the text width)
    Any idea how I can correct this?

    ReplyDelete
  7. Hi,
    I haven't seen a problem like that before where the balloon is too big. I don't calculate the size of the error tip, it should automatically size itself based on the text.
    You might try changing the code in the ErrorTipManager.createErrorTip() function and see if you can make the error tip the correct size.

    ReplyDelete
  8. Hi Chris,
    Thanks for you comment.
    I already added some code to get it right, like you suggest, but it's strange that it happens in the first place.

    added: errorTip.width = .9 * errorTip.width;
    added: errorTip.height = .9 * errorTip.height;

    Looks perfect now.

    But can you explain what the tt var does? It looks like you make it the same ToolTip as "errorTip" and then you set the style, but you don't use tt var later on in the return or display. Or am I missing something here?

    // set the styles to match the real error tooltip
    var tt:ToolTip = ToolTip(errorTip);
    tt.styleName = "errorTip";

    Thanks for sharing your code and helping out.
    Regards,
    Oscar

    ReplyDelete
  9. Hi Oscar,

    The only point of the variable tt is so that I can set the styleName to "errorTip", this makes the tooltip look like the red error tips. The errorTip variable is of type IToolTip, which doesn't expose the styleName property.
    I probably should have just used one line to simplify it:
    ToolTip(errorTip).styleName = "errorTip";

    ReplyDelete
  10. The code didn't take into consideration about listeners (for my custom validator validating multiple controls), so it needs to be updated:

    /**
    * Called when the validator fires the valid event.
    * Hides the error tooltip if it is visible.
    */
    public static function validHandler(event:ValidationResultEvent):void {
    // the target component is valid, so hide the error tooltip
    var validator:Validator = Validator(event.target);
    hideErrorTip(validator.listener != null ? validator.listener : validator.source);
    // ensure that the source listeners were added
    addValidatorSourceListeners(validator);
    }

    /**
    * Called when the validator fires an invalid event.
    * Shows the error tooltip with the ValidatorResultEvent.message as the error String.
    */
    public static function invalidHandler(event:ValidationResultEvent):void {
    // the target component is invalid, so show the error tooltip
    var validator:Validator = Validator(event.target);
    showErrorTip(validator.listener != null ? validator.listener : validator.source, event.message);
    // ensure that the source listeners were added
    addValidatorSourceListeners(validator);
    }

    ReplyDelete
  11. Thanks for the last post. I didn't know what the listener property was for until I saw your post.
    Chris

    ReplyDelete
  12. Thanks for the tips! When i have more than one textInput field in the popup, the tooltip of the second field doesnt move when i move the popup, am I missing something?

    Thanks!

    ReplyDelete
  13. Good catch. I had only added support for one validator per popup.

    I've made a change now in the ErrorTipManager so that it now supports multiple validators per popup. I renamed the unregisterValidatorOnPopUp(validator, popUp) function to unregisterPopUpValidators(popUp). The validator no longer needs to be passed in since the ErrorTipManager keeps a record of all the validators that are registered to the popup.

    I also updated the example shown above. Thanks for your comment.
    Chris

    ReplyDelete
  14. Thank you very much for your quick response! I am a fairly new to Flex , I was trying to fix it but I couldn't get the tool tip to move with the control.

    This work perfectly well with the application I am working on right now!

    Again, thank you for sharing!

    - Priscilla

    ReplyDelete
  15. I can't see any explicit licensing on this piece code so was wondering if it was ok to use in commerical application.

    Thanks,
    Noella

    ReplyDelete
  16. Sure Noella, you can use it in a commercial application.
    Chris

    ReplyDelete
  17. This is great, exactly what I needed. I also have a little bit of an issue with the positioning, the "real" error tip is placed above my text box because there is not enough room on the screen to fit it to the right. But this code still wants to put it off to the right. I also had the issue with the balloon being too wide (but mine was the correct height).

    Anyway, minor issues I'm sure I can fix. At any rate you saved me a bunch of time. Thanks!

    ReplyDelete
  18. I have been looking for a solution like this but I seem to be having trouble viewing the example and source code. Is the server down temporarily or did you move the code somewhere else?

    ReplyDelete
  19. it works now...Great work, Thanks a lot

    ReplyDelete
  20. It seems that I find a bug:
    when use mx.validators.Validator.validateAll to validator,the error tooltip does not disapear any more

    how to fix it?

    ReplyDelete
  21. The validation messages don't seem to reposition if the input fields are placed inside a scroller and you scroll up and down.

    Is there a good workaround for this?

    Thx,
    Pete

    ReplyDelete
  22. Hi Anonymous,
    I've tested using the Validator.validateAll([ validator ]) function and it seems to work fine for me. The error tip shows up, and then once I enter in some text to make it valid the error tip goes away. If you are still having trouble please feel free to post your example and I'll try to debug it.
    Thanks,
    Chris

    ReplyDelete
  23. Hi Pete,

    I've updated the example above to contain a scrolling box. I had to make a fix to the ErrorTipManager class to listen for scroll events on the parent containers. Seems to work quite nicely. It also will hide the error tip if the source component is scrolled out of the view.

    Chris

    ReplyDelete
  24. Hi Chris,

    great example, it help a lot, but I have issue with hideAllErrorTips method, it not disable tip on field that has focus.
    Can you help with it?
    Also I found another issue in method showErrorTip, it shows tip even if field is valid. I'm added
    check on empty error:
    if (errorTip && errorTip.text != ""){}
    and now its work fine for me.

    Thanks,
    Alex

    ReplyDelete
  25. Great Example... Thanks a ton...

    ReplyDelete
  26. Hi Alex,

    When I use the hideAllErrorTips() function it works fine for me. Are you doing anything special? I just added a button that when clicked calls ErrorTipManager.hideAllErrorTips(), and it doesn't seem to matter which field has focus, the error tip is hidden.

    As for your second point - the issue with the showErrorTip() function. If that works for you then that is great, but I don't think it should care what the value of errorTip.text is. The point of the showErrorTip() function is to show the error tip! It should get called only when the validator is invalid, just like hideErrorTip() which gets called when the validator is valid.

    Chris

    ReplyDelete
  27. Hi Chris,

    according to first issue you couldn't replicate it, because when you click on button it gets the focus, and all works fine in that case. But I have another situation: I have popup window with fields, and when I press close button(TitleWindow has closeButton) and shows alert (and that's why I need to hide all error tooltip), but when i press close button, focus remains in not valid component, and errorTip didn't disapear.
    I found workaround: just need to set stage.focus=null.

    Regarding to second issue, maybe you right, in my situation, even if field is valid, it show empty error, and I think its wrong.

    Thanks,
    Alex

    ReplyDelete
  28. That makes sense Alex, I didn't realize it was a focus issue.
    Chris

    ReplyDelete
  29. Great example!

    Just one question:

    Is there an easy to to add an icon in front of the error text?

    ReplyDelete
  30. There isn't an easy way to add an icon to the error tip.

    If you look inside the ErrorTipManager.createErrorTip() function, you'll see the line
    errorTip = ToolTipManager.createToolTip(error, position.x, position.y);
    This is where the tooltip gets created, and is of type ToolTip. There is nothing in the ToolTip class that supports icons, so one solution is you could manually add your icon to the tooltip object right after this line, something like this:

    // embed your icon, put at the top of ErrorTipManager.as
    [Embed(source="assets/icon.gif")]
    private static const ICON:Class;

    // Inside the createErrorTip() function
    var tt:ToolTip = (errorTip as ToolTip);
    // add your icon to error tip
    var image:IFlexDisplayObject = new ICON();
    tt.addChild(image as DisplayObject);
    // position the icon, choosing the x-value is tricky
    // it depends on where the tooltip gets displayed
    // on the right, below, or above the input field.
    var ttW:Number = tt.getExplicitOrMeasuredWidth();
    var ttH:Number = tt.getExplicitOrMeasuredHeight();
    var padLeft:int = int(tt.getStyle("paddingLeft"));
    image.move(padLeft + 4, (ttH - 16)/2);
    // Adjust the tooltip's size to include the icon's width
    tt.setActualSize(ttW + 18, ttH);
    // add padding on left for the icon
    tt.setStyle("paddingLeft", padLeft + 16);

    Another option would be to created your own class that extends ToolTip, and do all the positioning and sizing in that class. But then you'd have to duplicate what the ToolTipManagerImpl.createToolTip() function does (adding it to the system manager).

    Good luck!
    Chris

    ReplyDelete
  31. Regarding your posting on March 24, to correct the problem when scrolling the parent container. I integrated your changes and they work great except when you use the mouse scroll wheel. I can replicate the problem using your scroll box example. If you grab the scroll bar with the mouse, the error tip moves smoothly, but when you use the scroll wheel, it jumps around. Nevertheless, this is an excellent tool. Thanks for sharing it.

    ReplyDelete
  32. Great example! Thanks!

    I noticed that when I use my mouse wheel to scroll up/down my parent application the ErrorTip Box moves to a incorrect position. Have you noticed it? Do you know how can i fix it?
    I looked into the source code and there is a method that gets ScrollEvents. It works when I scroll it down with my mouse click.
    Thanks in advance

    ReplyDelete
  33. Thanks for letting me know about the scroll wheel problem.
    I've made a small update to the ErrorTipManager class to fix the problem. It's not a very clean solution, but does seem to work okay.
    Chris

    ReplyDelete
  34. It works perfectly fine.
    Great work

    ReplyDelete
  35. Great class Chris. Unfortunately handling ErrorTips is not as easy as it seems. Dealing with usability and UI issues can be very frustrating.

    Your class was a great shortcut to me and I can't thank you enough. I'm currently struggling with popup revalidating issues, and so far I've made two additions:

    1) updateErrorTipPosition function
    if (makeVisible && !errorTip.visible && (target as UIComponent).errorString != "") {

    added the last condition to avoid previously shown ErrorTips to reappear after re-validating

    2) resetErrorTips function

    public static function resetErrorTips() :void {
    for each (var errorTip:* in errorTips) {
    if (errorTip && errorTip is IToolTip) {
    errorTip.visible = false;
    ToolTipManager.destroyToolTip(errorTip);
    }
    }
    errorTips = null;
    errorTips = new Dictionary();
    errorTips.weakKeys = true;
    }

    added this to deal with problems that arise when you try to revalidate a form.

    I´m not sure if there's a better way but those changes are working well so far.

    Best regards, Claudio

    ReplyDelete
  36. Thanks for those updates Claudio, much appreciated. I agree, showing error tips is not nearly as easy as I originally thought it would be. More and more problems keep coming up.
    Chris

    ReplyDelete
  37. Hello Chris,
    I´ve been working with you ErrorTipManager and it´s been of great use.
    Right now, I´m trying to do something similar to the 'positionErrorTip' method.
    I have a 'continue' button that only jumps to the next screen if all validators.results returns null.
    I´ve been trying to reposition my 'continue' button to the center of right side of the screen without success.
    How am I supposed to get how many pixels the user have scrolled?

    ReplyDelete
  38. Hi Rogerio,

    If I understand you correctly - to get how many pixels the user has scrolled you can use the verticalScrollPosition property on the Container. For horizontal scrolling use the horizontalScrollPosition property.

    The verticalScrollPosition is "the current position of the vertical scroll bar. This is equal to the distance in pixels between the top edge of the scrollable surface and the topmost piece of the surface that is currently visible.".

    So you'd probably want to use that value and add half of your container's height to center the continue button vertically.

    Chris

    ReplyDelete
  39. Hey Chris,

    Great util. One thing, this will introduce a good sized memory leak as all your event listeners to each of the controls and the objects used as dictionary keys all have strong references. If you profile your sample app and watch the instance count of TitleWindow as you click the "Show PopUp" button and close the windows several times. These references won't allow any of the controls parented by these transient containers, nor the containers themselves to ever be garbage collected.

    The simple fix to this would be to create your dictionaries specifying the first param to use weak references for the keys and to register each event listener with weak references. E.g.:

    private static var errorTips:Dictionary = new Dictionary(true);

    and

    validator.addEventListener(ValidationResultEvent.VALID, validHandler, false, EventPriority.DEFAULT, true);

    These are just a couple of the places the change needs to be made, just syntax examples.

    ReplyDelete
  40. Hi Beau,
    Thanks very much for the comment. I haven't used weak references much, and didn't even think about it. But you're right, I ran the profiler and opened the popup window 10 times and found many instances of the TitleWindow lingering.
    I've updated the code above with your suggestions.
    Thanks again,
    Chris

    ReplyDelete
  41. Thank you very much. Your solution was really helpful

    Regards
    mukund

    ReplyDelete
  42. I have another issue with this component

    I have a component objCanvas:Canvas within which I am using ErrorTipManager to perform validation and display errors.
    When there is an error and when the error message is being dispalyed, if I navigate to some other component. I see the red coloured error box still. I doesn't vanish

    Regards
    mukund

    ReplyDelete
  43. Hi Mukund,

    I think the problem you are noticing is actually the way it is supposed to work.

    By default when a validator runs and is invalid, the red error border shows up around the input field. My ErrorTipManager simply makes the Error tool tip show up when the input field isn't in focus.

    Try your problem without using the ErrorTipManager and I think you'll find that the red error border will show up on a field even after it loses focus.

    One thing you could do to get around this is to clear the errorString property on the UIComponent input field. The red border automatically shows up when that errorString property isn't null or empty.

    Chris

    ReplyDelete
  44. Hi Chris,

    I think I was not clear with my point.

    For example
    Consider a component, say objCanvas1 which is having some text controls. I have included the ErrorTipManager to validate data and display errors if any.

    Let us assume that the textcontrol have a minimum length of 5characters. When I typed 2 characters, it displays th errors to me.

    On some action in objCanvas1, I use the removeChild method to remove objCanvas1 and I am adding another component objCanvas2.

    In this case, I see the error message still getting displayed which should have not been.

    I hope I am clear now, if not, please let me know, will clarify it

    ReplyDelete
  45. Thank you very much. Your solution was really helpful!

    Mathieu

    ReplyDelete
  46. Hi,

    There is a scroll issue when there is no tip error and you scroll it up or down.

    How to reproduce:
    1. insert some text in the text input (Scroll Box)
    2. Click in another TextInput (and the tip error will disapear)
    3. Scroll up or down (and the tip error will show again)

    How to solve:
    In the parentContainerScrolled method, where you have
    "// re-position the error tip, also will make it visible if it was hidden"
    you cannot force the hidden error tips to show [should be updateErrorTipPosition(target); ]


    I don't know if this fix opens other issues, but it solves this problem.

    ReplyDelete
  47. Thanks a lot for your comment Tiago.

    Your fix actually does introduce a new problem - that one line:
    updateErrorTipPosition(target, true);
    Hides the error tips when they are scrolled out of the visible viewport, and shows them when the input control is scrolled back into view.

    The better solution is to change the ErrorTipManager.validHandler() function to call removeErrorTip(...) instead of hideErrorTip(...). This way whenever a component is valid the error tip is removed from the ErrorTipManager's cache. This is probably better anyway, even if it means the error tips will be created every time.

    Chris

    ReplyDelete
  48. Thanks for this!

    I seem, however to be having trouble related to multiple validators on a single field.

    I have an email field, and I'm using a standard emailvalidator, and a custom validator that works with my database remotely, to verify the uniqueness of the entered email.

    When ever I just use one of the validators, your solution works very well, but when adding a second, then I get all sorts of unstable behavior.

    Any thoughts ?

    Thanks Again!

    ReplyDelete
  49. Chris, this is great work, thanks for sharing it. I have been trying to use this in Flex 4 which work well except that is does not handle scrolling when inside a Scroller (as mentioned by digio above). This appears to be because the Scroller does not fire Move events like the scroll bars do in Flex 3.

    I'm a novice Flex dev and the only way I could find to get this working was to listen for PropertyChangeEvents on the UIComponent and act on changes to horizontalScrollPosition or verticalScrollPosition. This is a bit messy so if anyone can suggest a better way of doing it I'm all ears.

    I have used the registerValidatorOnPopUp(...) functions as these pass in the container component, in my case a Group wrapped in a Scroller. I extended the registerValidatorOnPopUp(...) function to register the event listener (and removed it in unregisterPopUpValidators(...)). I also filter out unwanted PCE's in targetMoved(...).

    These changes seem to work most of the time but you get some 'odd' results when scrolling fast, as if it misses an event and then to tips can end up in the wrong place.

    Code changes below:

    public static function registerValidatorOnPopUp(validator:Validator, popUp:UIComponent, hideExistingErrorTips:Boolean = false):void
    {
    ...
    // add move/resize listeners on the popUp to keep the error tip positioned properly
    popUp.addEventListener(MoveEvent.MOVE, targetMoved, false, 0, true);
    popUp.addEventListener(ResizeEvent.RESIZE, targetMoved, false, 0, true);

    // add propertyChange listener to detect scrolling in Flex4 Scroller
    popUp.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, targetMoved, false, 0, true);

    ...
    }

    public static function unregisterPopUpValidators(popUp:UIComponent, validateExistingErrorTips:Boolean = false):void {
    ...
    // remove the move/resize listeners on the popUp
    popUp.removeEventListener(MoveEvent.MOVE, targetMoved);
    popUp.removeEventListener(ResizeEvent.RESIZE, targetMoved);

    popUp.removeEventListener(PropertyChangeEvent.PROPERTY_CHANGE, targetMoved);

    ...
    }


    private static function targetMoved(event:Event):void {
    if (isExcludedEvent(event)) return;
    ...
    }

    // filter non scroll property events and duplicate scroll property events
    static private function isExcludedEvent(event:Event):Boolean {
    if (event.type == PropertyChangeEvent.PROPERTY_CHANGE && event.property != "horizontalScrollPosition" && event.property != "verticalScrollPosition" ) {
    return true;
    }
    if (event.type == PropertyChangeEvent.PROPERTY_CHANGE && (event as PropertyChangeEvent).source != event.currentTarget) {
    return true;
    }
    return false;
    }


    [winge] code formatting in these comments sucks!!![/winge]

    Hope this can help some others.
    Colin.

    ReplyDelete
  50. Hi, I wanted to perform validateAll on the form after the user hits next and then prevent navigation away from the form if validation fails. I have modified the validateAll() method return a Boolean result - True if all validaiton passes, False otherwise. The code is below.

    /**
    * Calls validate() on all the validators.
    * Returns true if all validation passes, else false
    */
    public static function validateAll():Boolean {
    var valid:Boolean = true;
    // need to validator to figure out which error tips should be shown
    for (var validator:Object in validators) {
    var validationResult:ValidationResultEvent = validator.validate();
    if (validationResult.results) {
    valid = false;
    }
    }
    return valid;
    }

    Hope this is useful to others too.
    cheers, Colin

    ReplyDelete
  51. Hi Chris,

    Thanks for this wonderful class !
    I'm using it in a professional environment and it's so helpful.

    As CashCow said, there is now a scroll bug using a parent scroller in Flex 4.1 . I didn't test CashCow code but can you confirm it's bug free or can you improved the class to make it usable?

    Cheers, Raphi

    ReplyDelete
  52. Issue: Red Glow remains when input box clicked and valid input entered.

    Fix: add the following tag to TextInputs - keyUp="txtAmount.drawFocus(true)"

    This is a bug logged on Flex bug site

    ReplyDelete
  53. I'm using this to validate a dynamically generated form and it works great:

    var ti:TextInput = new TextInput();
    var phoneValid:PhoneNumberValidator = new PhoneNumberValidator();
    phoneValid.source = ti;
    phoneValid.property = "text";
    phoneValid.required = true;
    ErrorTipManager.registerValidator(phoneValid);
    phoneValid.validate();
    this.addChild(ti);

    Nice work!

    ReplyDelete
  54. This is a great tool! I'm having trouble using it with the CreditCardValidator class, though--the ErrorTips aren't visible unless you mouse over the corresponding fields.

    I'm thinking this has something to do with the fact that CreditCardValidator is validating two separate fields, a "cardNumber" and a "cardType" field?

    Is there a way to get the ErrorTipManager working with the CreditCardValidator component?

    -Josh

    ReplyDelete
  55. CashCow's fix didn't work for me, but got me started on a fix that *did* work for me. I posted about that here:
    http://forums.adobe.com/message/3516361#3516361

    ReplyDelete
  56. Hi Chris,

    thanks a lot for sharing this. It is very useful.

    I encountered an issue: if i replace the default validator messages inside the validator tag using the property e.g. requiredFieldError="some rather long Text", the tooltip size isn't correct. It seems to keep the size of the original text and the new text overlaps the tooltip. The text is coming from a localization class which works with standard validators.

    Do you have an idea how to fix this?

    Any help is greatly appreciated!

    Sab

    ReplyDelete
  57. Hi Sab,

    I don't know how to fix this problem. I spent a few minutes looking at it, but I didn't find a way to get the label displayed fully.

    If you're interested I've put up a new blog post today on an alternate method displaying form validation errors.

    Chris

    ReplyDelete
  58. Hello,

    There is one case where any error tips that are being displayed will not track their targets when those targets are repositioned. That is when the browser is resized. You can see this in the sample application if you wrap the components in say a VBox, eg.

    <mx:VBox width="100%" height="100%" horizontalAlign="center" verticalAlign="middle">

    .
    . Sample application components.
    .
    </mx:VBox>


    If you run the application and resize the browser, the error tips will be misaligned.

    To remidy this, simply add this code to ErrorTipManager.


    import mx.core.Application;

    /**
    * Adds an event listener for when the browser resizes.
    */
    private static var stageResize:* = Application.application.addEventListener(ResizeEvent.RESIZE, applicationResized, false, 0, true);

    /**
    * When the browser is resized we need make the error tips track their targets.
    */
    private static function applicationResized(event:Event):void
    {
    for (var target:Object in errorTips) {
    handleTargetMoved(target as DisplayObject);
    }
    }

    Patrick

    ReplyDelete
  59. Great class and thanks Patrick Groves for your update. Required that functionality as well as we noticed that limitation!

    ReplyDelete