Не так давно я начал разрабатывать сайты на ASP.NET MVC и в одном из моих проектов у меня появилась потребность в нестандартном валидаторе, который проверял бы обязательность заполнения элемента формы в зависимости от значения другого элемента. Именно об этом я и хочу рассказать.
Сайт разрабатывался на автомобильную тематику. Необходимость в валидаторе появилась на форме регистрации. Пользователь может зарегистрироваться как частное лицо и как автодиллер. Если пользователь хочет зарегистрироваться как автодиллер, то ему необходимо заполнить несколько дополнительных обязательных полей. Можно было конечно сделать регистрацию в несколько этапов, но хотелось чтобы весь процесс регистрации проходил за один шаг.
Чтобы создать свой собственный валидатор, нам необходимо унаследоваться от класса ValidationAttribute.
Определим для атрибута сообщение об ошибке, которое будет выдаваться пользователю в _defaultErrorMessage, а так же определим два поля _targetPropertyName и _targetPropertyCondition, в которых будет храниться имя поля в модели, в зависимости от которого будет проверяться обязательность заполнения текущего поля (для которого указан данный атрибут) и значение этого поля соответственно.
Для того чтобы реализовать клиентскую валидацию необходимо унаследовать интерфейс IClientValidatable. В методе GetClientValidationRules создаем новое правило для которого указываем сообщение об ошибке, тип валидатора, а так же параметры нашего валидатора. В последствии все это добавится в разметку формы.
На этом серверная часть закончена. Перейдем к клиетской части. Для того что наш валидатор заработал на стороне клиента нам необходимо создать свою функцию валидации и свой адаптер.
Для того чтобы использовать необходимо указать в модели для соответствующих полей атрибут RequiredIf:
А так же добавить на страницу наш скрипт:
В результате мы получили достаточно удобный в использовании валидатор, который работает и на серверной и на клиентской стороне:
PS: По умолчанию в ASP.NET MVC3 режим ненавязчивой валидации отключен. Включить его можно двумя способами. Первый, используя файл Web.config:
Так же можно указать в коде:
а так же необходимо добавить пару JavaScript файлов во View:
Сайт разрабатывался на автомобильную тематику. Необходимость в валидаторе появилась на форме регистрации. Пользователь может зарегистрироваться как частное лицо и как автодиллер. Если пользователь хочет зарегистрироваться как автодиллер, то ему необходимо заполнить несколько дополнительных обязательных полей. Можно было конечно сделать регистрацию в несколько этапов, но хотелось чтобы весь процесс регистрации проходил за один шаг.
Серверная часть
Чтобы создать свой собственный валидатор, нам необходимо унаследоваться от класса ValidationAttribute.
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
public sealed class RequiredIfAttribute : ValidationAttribute, IClientValidatable
{
//Сообщение, которое будет выводиться пользователю.
private const string _defaultErrorMessage = "{0} is required";
//Целевое поле
private string _targetPropertyName;
//Значение целевого поля
private bool _targetPropertyCondition;
public RequiredIfAttribute(string targetPropertyName, bool targetPropertyCondition)
: base(_defaultErrorMessage)
{
this._targetPropertyName = targetPropertyName;
this._targetPropertyCondition = targetPropertyCondition;
}
public override string FormatErrorMessage(string name)
{
return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString, name, _targetPropertyName, _targetPropertyCondition);
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
bool result = false;
bool propertyRequired = false; // Флаг для проверки обязательности заполнения текущего поля.
//Получим целевое поле
var targetProperty = validationContext.ObjectType.GetProperty(_targetPropertyName);
//Получим значние целевого поля
var targetPropertyValue = (bool)targetProperty.GetValue(validationContext.ObjectInstance, null);
//Если значение целевого поля соответствует заданному, то токущее поле должно быть заполнено.
if (targetPropertyValue == _targetPropertyCondition)
{
propertyRequired = true;
}
if (propertyRequired)
{
//Если поле не заполнено
if (value == null)
{
var message = FormatErrorMessage(validationContext.DisplayName);
return new ValidationResult(message);
}
}
return null;
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
var rule = new ModelClientValidationRule();
rule.ErrorMessage = FormatErrorMessage(metadata.GetDisplayName());
rule.ValidationType = "requiredif";
rule.ValidationParameters.Add("targetpropertyname", this._targetPropertyName);
rule.ValidationParameters.Add("targetpropertyvalue", this._targetPropertyCondition.ToString().ToLower());
yield return rule;
}
}
Определим для атрибута сообщение об ошибке, которое будет выдаваться пользователю в _defaultErrorMessage, а так же определим два поля _targetPropertyName и _targetPropertyCondition, в которых будет храниться имя поля в модели, в зависимости от которого будет проверяться обязательность заполнения текущего поля (для которого указан данный атрибут) и значение этого поля соответственно.
Для того чтобы реализовать клиентскую валидацию необходимо унаследовать интерфейс IClientValidatable. В методе GetClientValidationRules создаем новое правило для которого указываем сообщение об ошибке, тип валидатора, а так же параметры нашего валидатора. В последствии все это добавится в разметку формы.
Клиентская часть
На этом серверная часть закончена. Перейдем к клиетской части. Для того что наш валидатор заработал на стороне клиента нам необходимо создать свою функцию валидации и свой адаптер.
$(function () {
$.validator.addMethod("requiredif", function (value, element, param) {
if ($(param.propertyname).is(':checked').toString() == param.propertyvalue) {
if (!this.depend(param, element))
return "dependency-mismatch";
switch (element.nodeName.toLowerCase()) {
case 'select':
var val = $(element).val();
return val && val.length > 0;
case 'input':
if (this.checkable(element))
return this.getLength(value, element) > 0;
default:
return $.trim(value).length > 0;
}
}
return true;
});
$.validator.unobtrusive.adapters.add("requiredif", ["targetpropertyname", "targetpropertyvalue"], function (options) {
if (options.element.tagName.toUpperCase() !== "INPUT" || options.element.type.toUpperCase() !== "CHECKBOX") {
options.rules["requiredif"] = {
propertyname: "#" + options.params.targetpropertyname,
propertyvalue: options.params.targetpropertyvalue
};
options.messages["requiredif"] = options.message;
}
});
} (jQuery));
Использование:
Для того чтобы использовать необходимо указать в модели для соответствующих полей атрибут RequiredIf:
public class RegisterModel
{
[Required]
[Display(Name = "First name")]
public string FirstName { get; set; }
[Required]
[Display(Name = "Last name")]
public string LastName { get; set; }
[Required]
[DataType(DataType.EmailAddress)]
[Display(Name = "Email address")]
[RegularExpression("^([A-Za-z0-9_\\-\\.])+\\@([A-Za-z0-9_\\-\\.])+\\.([A-Za-z]{2,4})$", ErrorMessage = "Not a valid email.")]
public string Email { get; set; }
[Display(Name = "Dealer")]
public bool IsDealer { get; set; }
[RequiredIf("IsDealer", true)]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 3)]
[Display(Name = "Dealer name")]
public string Name { get; set; }
}
А так же добавить на страницу наш скрипт:
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.requiredif.js")" type="text/javascript"></script>
В результате мы получили достаточно удобный в использовании валидатор, который работает и на серверной и на клиентской стороне:
PS: По умолчанию в ASP.NET MVC3 режим ненавязчивой валидации отключен. Включить его можно двумя способами. Первый, используя файл Web.config:
<appSettings>
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>
Так же можно указать в коде:
HtmlHelper.ClientValidationEnabled = true;
HtmlHelper.UnobtrusiveJavaScriptEnabled = true;
а так же необходимо добавить пару JavaScript файлов во View:
<script src="@Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script>