Flex: How do you validate 2 password fields to make sure they match?

14,847

Solution 1

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"/>

Solution 2

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>

Solution 3

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();
    }
}
Share:
14,847
Shawn
Author by

Shawn

a long time ago i found an xss vuln here and took down the entire site userid 26, respect

Updated on July 01, 2022

Comments

  • Shawn
    Shawn about 2 years

    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.

  • Kel
    Kel over 14 years
    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 :)
  • blong
    blong about 13 years
    @Kel and @Marty Pitt , is this now fixed on Marty's site? I need to do this sort of asynchronous validation and this "framework" looks like just the thing! I'm just a bit nervous about trying to implement it, if there is a bug