ASP.Net MVC 3 - ненавязчивая проверка на стороне клиента для шаблонов редактора
Я новичок в ASP.Net MVC 3, столкнувшись с некоторыми проблемами при попытке реализации ненавязчивой проверки на стороне клиента для шаблона редактора, который я создал для отображения даты в произвольном порядке.
UI
Мне нужно, чтобы показать дату в формате трех текстового интерфейса как
Я установил EditorTemplate для отображения даты в трех частях:
@model DateTime?
<table class="datetime">
<tr>
<td>@Html.TextBox("Day", (Model.HasValue ? Model.Value.ToString("dd") : string.Empty)) </td>
<td class="separator">/</td>
<td>@Html.TextBox("Month", (Model.HasValue ? Model.Value.ToString("MM") : string.Empty))</td>
<td class="separator">/</td>
<td>@Html.TextBox("Year", (Model.HasValue ? Model.Value.ToString("yyyy") : string.Empty))</td>
</tr>
<tr>
<td class="label">dd</td>
<td/>
<td class="label">mm</td>
<td/>
<td class="label">yyyy</td>
</tr>
</table>
модель
Я должен связать поле Дата рождения, которое является свойством подобъекта моей модели, с этим свойством в этой структуре.
MyModel
--> MySubModel
--> DateOfBirth
public class MySubModel
{
...
[DataType(DataType.Date)]
[Display(Name = "Date of birth")]
[DateTimeClientValidation()]
public DateTime DateofBirth { get; set; }
...
}
Проверка клиентов
Я поставил пользовательский атрибут проверки, который реализует IClientValidatable как
public class DateTimeClientValidationAttribute : ValidationAttribute, IClientValidatable
{
...
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
List<ModelClientValidationRule> clientRules = new List<ModelClientValidationRule>();
//Combined date should be valid
ModelClientValidationRule validDateRule = new ModelClientValidationRule
{
ErrorMessage = "Please enter a valid date.",
ValidationType = "validdate"
};
validDateRule.ValidationParameters.Add("dayelement", metadata.PropertyName + ".Day");
validDateRule.ValidationParameters.Add("monthelement", metadata.PropertyName + ".Month");
validDateRule.ValidationParameters.Add("yearelement", metadata.PropertyName + ".Year");
clientRules.Add(validDateRule);
return clientRules;
}
...
}
Я пытаюсь передать имена элементов текстовых полей "День", "Месяц" и "Год" в элементы проверки на стороне клиента, чтобы позже я напишу метод проверки подлинности jQuery на стороне клиента и адаптер, который будет использовать эти элементы и выполнять проверку на стороне клиента.
Посмотреть
Теперь, чтобы использовать этот шаблон редактора, я вставил в View следующие строки
@model MyModel
...
<tr>
<td class="editor-label">
@Html.LabelFor(m => m.MySubModel.DateofBirth)
</td>
<td class="editor-field">
@Html.EditorFor(m => m.MySubModel.DateofBirth)
@Html.ValidationMessageFor(m => m.MySubModel.DateofBirth)
</td>
</tr>
...
Добавлены все соответствующие файлы проверки jquery в виде ссылок
Вопросы
- Это не выводит ненавязчивые атрибуты проверки JavaScript в html, хотя я реализовал IClientValidatable. В целях тестирования, когда я помещаю тот же атрибут (DateTimeClientValidation) в другое свойство в модели, в которой не использовался этот шаблон редактора, он выводит эти атрибуты проверки, а не только для этого шаблона редактора. Где я мог пойти не так?
- Что касается диапазона сообщения проверки для шаблона редактора, правильно ли, что я поместил его только в представление или я должен поместить его непосредственно в шаблон редактора (@ Html.ValidationMessageFor (m => m.MySubModel.Date of Birth))
- В этом примере, я прав в дизайне, я поместил в DateTimeClientValidationAttribute, который на самом деле является атрибутом, который я надел на модель, но этот компонент немного знает о пользовательском интерфейсе (так как он пытается выдавать элементы Day, Month & Year имя клиенту), это позволяет модели немного узнать о View, нарушаю ли я какие-либо принципы проектирования?
- В DateTimeClientValidationAttribute я пытаюсь передать клиенту имена элементов дня, месяца и года, чтобы клиентский сценарий мог выполнить проверки на нем. Но так как свойство модели Date of Birth находится в подобъекте, фактическое имя элемента в сценарии - MySubObject.DateOfBirth, что делает имя текстового поля Day равным MySubObject.DateofBirth.Day. Как найти полное имя модели в методе GetClientValidationRules?, чтобы я мог передать имя клиенту?
Спасибо за терпение, чтобы прочитать все это, и за ответы
2 ответа
После некоторых усилий я заставил контроль работать, вставляя, если это кому-нибудь пригодится.
Первым делом нужно определить элемент управления как
@model DateTime?
<table class="datetime">
<tr>
<td>@Html.TextBox("", (Model.HasValue ? Model.Value.ToString("dd") : string.Empty)) </td>
<td class="separator">/</td>
<td>@Html.TextBox("", (Model.HasValue ? Model.Value.ToString("MM") : string.Empty))</td>
<td class="separator">/</td>
<td>@Html.TextBox("", (Model.HasValue ? Model.Value.ToString("yyyy") : string.Empty))</td>
</tr>
<tr>
<td class="label">dd</td>
<td/>
<td class="label">mm</td>
<td/>
<td class="label">yyyy</td>
</tr>
</table>
Убедитесь, что вы даете пустые строки в качестве имени для всех трех текстовых полей, это заставляет инфраструктуру MVC генерировать одинаковое имя, соответствующее Model DateofBirth для всех трех текстовых полей на стороне клиента. Кроме того, ненавязчивые параметры проверки javascript будут сгенерированы для первого текстового поля в списке, поскольку это первый случай элемента управления для редактирования с именем модели.
На стороне клиента при любом событии в любом из этих текстовых полей запускаются все соответствующие события проверки, поскольку все эти 3 текстовых поля имеют одно и то же имя.
Вдобавок к обычным проверкам, как требуется,... мы должны написать пользовательскую процедуру проверки клиента, которая объединит все эти три значения и проверит, образует ли объединенное значение действительную дату. Это может быть достигнуто как в ответе Jeff Dalley.
Хорошо, так несколько вещей. Первое - если это вообще возможно, не разбивайте дату на три поля. Вы избавите себя от головной боли, просто настроив его как одно поле с некоторой проверкой и, возможно, с помощью DatePicker в jQueryUI.
Затем, в вашем пользовательском коде атрибута внутри DateTimeClientValidationAttribute, вы никогда не проверяете, является ли дата действительной, путем реализации IsValid:
protected override ValidationResult IsValid(object value,
ValidationContext validationContext)
{
...
// Put date parts together and check is valid...
if (DateTime.TryParse(year+"/"+month+"/"+day, out dateResult))
return ValidationResult.Success;
// Not valid
return new ValidationResult(String.Format(ErrorMessageString,
validationContext.DisplayName));
}
Затем вам нужно будет создать ненавязчивый адаптер проверки и метод проверки jQuery, который собирает параметры вместе и пытается разобрать дату:
jQuery.validator.unobtrusive.adapters.add(
'validdate', // notice this is coming from how you named your validation rule
['dayelement'],
['monthelement'],
['yearelement']
function (options) {
options.rules['datepartcheck'] = options.params;
options.messages['datepartcheck'] = options.message;
}
);
jQuery.validator.addMethod('datepartcheck', function (value, element, params) {
var year = params[2];
var month = params[1];
var day = params[0];
var birthDate = year + '/' + month-1 + '/' + day;
var isValid = true;
try {
// datepicker is a part of jqueryUI.
// include it and you can take advantage of .parseDate:
$.datepicker.parseDate('yy/mm/dd', birthDate);
}
catch (error) {
isValid = false;
}
return isValid;
}, '');