tags:

views:

5259

answers:

6

I want to use a validator to ensure 2 password fields match in Flex. I want the validator to highlight form fields like a normal flex validation control. Thanks.

A: 

Unless you have to use a validator, you can simply attach a change event handler and set errorString property of the password field when the passwords don't match. It gives the same highlighting as done by validator.

Chetan Sastry
+3  A: 

enter code hereI created my own custom validator (mostly copied from date validator):

package validators
{
    import mx.validators.ValidationResult;
    import mx.validators.Validator;

    public class PasswordValidator extends Validator
    {
     // Define Array for the return value of doValidation().
        private var results:Array;

     public function PasswordValidator()
     {
      super();
     }

     public var confirmationSource: Object;
     public var confirmationProperty: String;

        // Define the doValidation() method.
        override protected function doValidation(value:Object):Array {

            // Call base class doValidation().
      var results:Array = super.doValidation(value.password);

            if (value.password != value.confirmation) {
       results.push(new ValidationResult(true, null, "Mismatch",
       "Password Dosen't match Retype!"));

            }

            return results;
        }    

     /**
      *  @private
      *  Grabs the data for the confirmation password from its different sources
      *  if its there and bundles it to be processed by the doValidation routine.
      */
     override protected function getValueFromSource():Object
     {
      var value:Object = {};

      value.password = super.getValueFromSource();

      if (confirmationSource && confirmationProperty)
      {
       value.confirmation = confirmationSource[confirmationProperty];
      }

      return  value;
     }  

    }
}

the example mxml for using:

<validators:PasswordValidator id="pwvPasswords" required="true" source="{txtPassword}" property="text" confirmationSource="{txtPasswordConfirm}" confirmationProperty="text" trigger="{btnStep2Finish}" />

It's pretty basic, but it's mostly what I need. It only highlights the password box though, would like to get it to highlight both.

A: 

Jack,

if you want highlight both password boxes couldn't you just duplicate your Passwordvalidator and switch source and confirmationSource.

Shua
+2  A: 

I've done this in a different way using custom validation rules.

Check it out: http://martypitt.wordpress.com/2009/08/26/rule-based-asynchronous-validation-in-flex-forms/

It shows how to do async validation (eg., checking a username is available on the server), and other validation scenario's that don't fit neatly into flex's out-of-the-box framework, including two passwords match.

Eg:

<mx:Button label="Register" enabled="{ validationRules.isValid }" />
<validation:ValidationRuleCollection id="validationRules">
      <validation:UsernameIsUniqueValidationRule username="{ txtUsername.text }" targetComponent="{ txtUsername }" />
      <validation:EmailIsUniqueValidationRule email="{ txtEmailAddress.text }" targetComponent="{ txtEmailAddress }" />
      <validation:PasswordsMustMatchValidationRule password1="{ txtPassword.text }" password2="{ txtPasswordConfirm.text }" targetComponent="{ txtPasswordConfirm }" />
      <mx:StringValidator required="true" source="{ txtUsername }" property="text" requiredFieldError="{ ResourceManager.getInstance().getString( ResourceBundles.ERROR_MESSAGES , 'REQUIRED_FIELD_ERROR' )}" />
</validation:ValidationRuleCollection>
Marty Pitt
Hey, I found a slight bug in your validation system. Basically the validation event handler wasn't wired for the standard flex validators.I've fixed it by changing the validationRules setter in ValidationRuleCollection, adding the addEventListener :)
Kel
+1  A: 

Here's a better custom validator that's more universal, clean, and works well with the 'required' field.

 import mx.validators.ValidationResult;
 import mx.validators.Validator;

 public class MatchValidator extends Validator{
  private var _matchSource: Object = null;
  private var _matchProperty: String = null;
  private var _noMatchError: String = "Fields did not match";

  [Inspectable(category="General", defaultValue="Fields did not match")]
  public function set noMatchError( argError:String):void{
   _noMatchError = argError;
  }
  public function get noMatchError():String{
   return _noMatchError;
  }

  [Inspectable(category="General", defaultValue="null")]
  public function set matchSource( argObject:Object):void{
   _matchSource = argObject;
  }
  public function get matchSource():Object{
   return _matchSource;
  }

  [Inspectable(category="General", defaultValue="null")]
  public function set matchProperty( argProperty:String):void{
   _matchProperty = argProperty;
  }
  public function get matchProperty():String{
   return _matchProperty;
  }


  override protected function doValidation(value:Object):Array {

   // Call base class doValidation().
   var results:Array = super.doValidation(value.ours);

   var val:String = value.ours ? String(value.ours) : "";
   if (results.length > 0 || ((val.length == 0) && !required)){
    return results;
   }else{
    if(val != value.toMatch){
     results.length = 0;
     results.push( new ValidationResult(true,null,"mismatch",_noMatchError));
     return results;
    }else{
     return results;
    }
   }
  }  

  override protected function getValueFromSource():Object {
   var value:Object = {};

   value.ours = super.getValueFromSource();

   if (_matchSource && _matchProperty){
    value.toMatch = _matchSource[_matchProperty];
   }else{
    value.toMatch = null;
   }
   return value;
  }
 }

Here's an example:

<components:MatchValidator source="{passwordCheckField}" property="text" matchSource="{passwordField}" matchProperty="text"
    valid="passwordsMatch = true" invalid="passwordsMatch = false" noMatchError="Passwords do not match"/>
Daniel
A: 

I expanded on Daniel's solution, adding the ability to trigger off of the matched source as well.

import flash.events.Event;

import mx.validators.ValidationResult;
import mx.validators.Validator;

public class MatchValidator extends Validator
{
    private var _matchSource: Object = null;
    private var _matchProperty: String = null;
    private var _noMatchError: String = "Fields did not match";

    [Inspectable(category="General", defaultValue="Fields did not match")]
    public function set noMatchError( argError:String):void{
        _noMatchError = argError;
    }
    public function get noMatchError():String{
        return _noMatchError;
    }

    [Inspectable(category="General", defaultValue="null")]
    public function set matchSource( argObject:Object):void{
        removeTriggerHandler();
        _matchSource = argObject;
        addTriggerHandler();
    }
    public function get matchSource():Object{
        return _matchSource;
    }

    [Inspectable(category="General", defaultValue="null")]
    public function set matchProperty( argProperty:String):void{
        _matchProperty = argProperty;
    }
    public function get matchProperty():String{
        return _matchProperty;
    }

    override protected function doValidation(value:Object):Array {

        // Call base class doValidation().
        var results:Array = super.doValidation(value.ours);

        var val:String = value.ours ? String(value.ours) : "";
        if (results.length > 0 || ((val.length == 0) && !required)){
            return results;
        }else{
            if(val != value.toMatch){
                results.length = 0;
                results.push( new ValidationResult(true,null,"mismatch",_noMatchError));
                return results;
            }else{
                return results;
            }
        }
    }  

    override protected function getValueFromSource():Object {
        var value:Object = {};

        value.ours = super.getValueFromSource();

        if (_matchSource && _matchProperty){
            value.toMatch = _matchSource[_matchProperty];
        }else{
            value.toMatch = null;
        }
        return value;
    }

    override public function set triggerEvent(value:String):void
    {
        removeTriggerHandler();
        super.triggerEvent = value;
        addTriggerHandler();
    }

    private function addTriggerHandler():void
    {
        if (_matchSource)
            _matchSource.addEventListener(triggerEvent,triggerHandler);
    }

    private function removeTriggerHandler():void
    {
        if (_matchSource)
            _matchSource.removeEventListener(triggerEvent,triggerHandler);
    }

    private function triggerHandler(event:Event):void
    {
        validate();
    }
}
Jeff