I assume you already followed Phil Haack's instructions here http://haacked.com/archive/2009/11/19/aspnetmvc2-custom-validation.aspx) on how to get custom validation working with MS AJAX client validation. To get it to work with jQuery, you'll need to modify the MicrosoftMvcJQueryValidation.js file:
In the __MVC_CreateRulesForField(validationField) function, you'll need to add a case statement. Continuing Phil's example, you'll need to add:
case "price":
__MVC_ApplyValidator_Price(rulesObj, thisRule.ValidationParameters["min"]);
break;
You'll then need to create the __MVC_ApplyValidator_Price function:
function __MVC_ApplyValidator_Price(object, value) {
// min is what jQuery Validate uses to validate for minimum values
object["min"] = value;
}
That should be enough to get Phil's example working.
Now, regarding your PropertiesMustMatchAttribute validation, it doesn't look like MVC generates the client-side json validation definition for attributes that decorate classes. Since PropertiesMustMatchAttribute must be used on the model (and not the property), I can't figure out how to make it trigger client-side validation. Instead, I took a different approach. I created a dummy validation attribute who's IsValid() overload always returns true, and used this attribute on a property. This is just a dummy attribute that will delegate the validation logic to jQuery validator's equalTo function. Here's the dummy attribute:
public class PropertiesMustMatchClientTriggerAttribute : ValidationAttribute
{
public string MatchProperty { get; set; }
public PropertiesMustMatchClientTriggerAttribute(string matchProperty)
{
MatchProperty = matchProperty;
ErrorMessage = "{0} doesn't match {1}.";
}
public override bool IsValid(object value)
{
return true;
}
public override string FormatErrorMessage(string name)
{
return String.Format(CultureInfo.CurrentCulture, ErrorMessageString, name, MatchProperty);
}
}
Here is the custom validator:
public class PropertiesMustMatchClientTriggerValidator : DataAnnotationsModelValidator<PropertiesMustMatchClientTriggerAttribute>
{
private string _message;
private string _matchProperty;
public PropertiesMustMatchClientTriggerValidator(ModelMetadata metaData, ControllerContext context, PropertiesMustMatchClientTriggerAttribute attribute)
: base(metaData, context, attribute)
{
_message = attribute.FormatErrorMessage(metaData.DisplayName);
_matchProperty = attribute.MatchProperty;
}
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
{
var rule = new ModelClientValidationRule
{
ErrorMessage = _message,
ValidationType = "equalTo"
};
rule.ValidationParameters.Add("matchField", _matchProperty);
return new[] { rule };
}
}
the above custom validator needs to be registered in Application_Start() per Phil's blog:
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(PropertiesMustMatchClientTriggerAttribute), typeof(PropertiesMustMatchClientTriggerValidator));
Finally, you need to modify the MicrosoftMvcJQueryValidation.js file:
- Add the following case statement to __MVC_CreateRulesForField:
case "equalTo":
__MVC_ApplyValidator_EqualTo(rulesObj, thisRule.ValidationParameters["matchField"]);
break;
function __MVC_ApplyValidator_EqualTo(object, elemId) {
object["equalTo"] = document.getElementById(elemId);
}
Now you need to attach the dummy validation attribute to a property:
[PropertiesMustMatchClientTrigger("Password")]
public string ConfirmPassword { get; set; }
That should do it.
Creating this dummy attribute is a bit ugly, so I hope someone can come up with a more elegant solution.