[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class ValidationGroupAttribute : ValidationAttribute
{
#region Properties
/// <summary>
/// Name of the validation group
/// </summary>
public string GroupName { get; set; }
#endregion
#region Constructor
public ValidationGroupAttribute(string groupName)
{
GroupName = groupName;
}
#endregion
#region Methods
public override bool IsValid(object value)
{
//No validation logic, always return true
return true;
}
#endregion
}We will also need a DataAnnotationsModelValidator for this attribute:
public class ValidationGroupValidator : DataAnnotationsModelValidator<ValidationGroupAttribute>
{
#region Fields
string _groupName;
#endregion
#region Constructor
public ValidationGroupValidator(ModelMetadata metadata, ControllerContext context, ValidationGroupAttribute attribute)
: base(metadata, context, attribute)
{
_groupName = attribute.GroupName;
}
#endregion
#region Methods
public override IEnumerable<ModelClientValidationRule> GetClientValidationRules()
{
//Add informations about validation group to metadata
var validatioRule = new ModelClientValidationRule
{
ErrorMessage = String.Empty,
ValidationType = "validationGroup"
};
validatioRule.ValidationParameters.Add("groupName", _groupName);
return new[] { validatioRule };
}
#endregion
}Don't forget to register above classes in your Global.asax:
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(ValidationGroupAttribute), typeof(ValidationGroupValidator));
So this is all we need on server side (please remember, that we don't want to achieve any server side logic, only partial validation on client side before posting the whole form). To make it work on client side, first we need to modify Sys.Mvc.FormContext._parseJsonOptions in MicrosoftMvcValidation.debug.js (or corresponding part in MicrosoftMvcValidation.js):
Sys.Mvc.FormContext._parseJsonOptions = function Sys_Mvc_FormContext$_parseJsonOptions(options) {
var formElement = $get(options.FormId);
var validationSummaryElement = (!Sys.Mvc._validationUtil.stringIsNullOrEmpty(options.ValidationSummaryId)) ? $get(options.ValidationSummaryId) : null;
var formContext = new Sys.Mvc.FormContext(formElement, validationSummaryElement);
formContext.enableDynamicValidation();
formContext.replaceValidationSummary = options.ReplaceValidationSummary;
for (var i = 0; i < options.Fields.length; i++) {
var field = options.Fields[i];
var fieldElements = Sys.Mvc.FormContext._getFormElementsWithName(formElement, field.FieldName);
var validationMessageElement = (!Sys.Mvc._validationUtil.stringIsNullOrEmpty(field.ValidationMessageId)) ? $get(field.ValidationMessageId) : null;
var fieldContext = new Sys.Mvc.FieldContext(formContext);
Array.addRange(fieldContext.elements, fieldElements);
fieldContext.validationMessageElement = validationMessageElement;
fieldContext.replaceValidationMessageContents = field.ReplaceValidationMessageContents;
for (var j = 0; j < field.ValidationRules.length; j++) {
var rule = field.ValidationRules[j];
//Here goes our small modification
if (rule.ValidationType == 'validationGroup') {
fieldContext.validationGroup = rule.ValidationParameters['groupName'];
}
else {
var validator = Sys.Mvc.ValidatorRegistry.getValidator(rule);
if (validator) {
var validation = Sys.Mvc.$create_Validation();
validation.fieldErrorMessage = rule.ErrorMessage;
validation.validator = validator;
Array.add(fieldContext.validations, validation);
}
}
}
fieldContext.enableDynamicValidation();
Array.add(formContext.fields, fieldContext);
}
var registeredValidatorCallbacks = formElement.validationCallbacks;
if (!registeredValidatorCallbacks) {
registeredValidatorCallbacks = [];
formElement.validationCallbacks = registeredValidatorCallbacks;
}
registeredValidatorCallbacks.push(Function.createDelegate(null, function () {
return Sys.Mvc._validationUtil.arrayIsNullOrEmpty(formContext.validate('submit'));
}));
return formContext;
}Now we can write ourselves function, which will perform partial validation based on group name:
Sys.Mvc.FormContext.validateGroup = function Sys_Mvc_FormContext$validateGroup(formId, groupName) {
//Get form element
var formElement = $get(formId);
//Get form context
var formContext = Sys.Mvc.FormContext.getValidationForForm(formElement);
//Get form fields
var fields = formContext.fields;
//Array for errors
var errors = [];
//For each field
for (var i = 0; i < fields.length; i++) {
var field = fields[i];
//If field has validation group and its name matches the one we are looking for
if (field.validationGroup && field.validationGroup == groupName) {
//Validate field
var fieldErrors = field.validate('submit');
if (fieldErrors) {
Array.addRange(errors, fieldErrors);
}
}
}
//Return true it there are no errors, otherwise false
return (!errors || !errors.length);
}And our job is done. Now we can call Sys.Mvc.FormContext.validateGroup('formId', 'validationGroup'); whenever we want to perform partial validation. I have created a sample application which make use of those modification, you can download it from my repository. If there is a need for same modification for jQuery validation, let me know and I will look into it.
Email
10 comments:
Genial dispatch and this enter helped me alot in my college assignement. Say thank you you for your information.
I had same problem and I was trying to use the code in link you provided https://tpeczek.svn.codeplex.com/svn/trunk/MVC/PartFormValidationExample/. But there is no Lib.Web.Mvc project in the code here.
You can find it here: https://tpeczek.svn.codeplex.com/svn/trunk/MVC/Lib.Web.Mvc/
Hi Tomas,
I think your article is great! but I need to implement it with asp.net mvc 3's unobtrusive validation,
Do you know where do I have to change the jquery.validate.unobtrusive.js file?
best regards
Hi Rodrigo,
I will look into this and let you know.
Greetings
Hi Rodrigo,
The ASP.NET MVC 3 jQuery client-side unobtrusive validation works a lot different than ASP.NET MVC 2 Microsoft client-side validation (for which the original solution was made). I'm not sure if this approach will work at all. I will keep on working on this, but as I have very limited time lately, this may take a while.
Greetings
Hi Tomasz. Did you get it with MVC 3?
Unfortunately I haven't - because of a new project my resources are too limited recently to take proper care of this subject. I will get back to this as soon as possible.
Tomasz, I got it!
The solution is here:
http://softwaredevelopmentsolutions.blogspot.com/2011/06/aspnet-mvc-3-partial-form-validation-on.html
Hi,
There's unbtrusive MVC3 client and server side implementation of validation groups in the 'MVC Validation Groups' CodePlex project (http://bit.ly/zRmxwD).
I wrote it specifically to handle tabbed UI's where validation summaries need to be split betweek multiple screens when there's a single 'submit' button.
A neat side affect is that it allows different validation to be performed based on different buttons.
Martin
Post a Comment