Цель высшего уровня : мне нужно рассчитать возраст человека, введя 2 даты - дату рождения и дату смерти.
Сведения о цели : эти даты следует вводить в виде отдельных полей - день, месяц, год (как показано на рисунке - способ ввода двух полей DateTime ).
Эти поля должны быть проверены для диапазона (день - 1..31, месяц - 1..12, год - 1900 ... ток) и для отношения - дата смерти должна быть больше даты рождения.
Вопрос : Как проверить соотношение двух дат, отобразить сообщения об ошибках, если я не создаю Editor для поля DateOfDeath3 (Date3GreaterThanAnother атрибут проверки применяется к этому полю)? Мне нужно подтвердить дату, но я отображаю только ее части - день, месяц, год.
Может быть, я выбрал неправильный подход для всего этого, пожалуйста, дайте мне подсказку, как это можно сделать лучше ...
Спасибо!
Сведения о текущей реализации : я уже реализовал ввод, сохранение, проверку дат (только на стороне сервера).
Для реализации ввода DateTime в виде отдельных полей я использую следующий класс:
public class Date3
{
/// <summary>
/// Creates Date3 instance with internal DateTime object set to null.
/// </summary>
public Date3()
{
DateTime = null;
}
public Date3(DateTime dateTime)
{
DateTime = dateTime;
Day = dateTime.Day;
Month = dateTime.Month;
Year = dateTime.Year;
}
public DateTime? DateTime { get; private set; }
/// <summary>
/// Recreates inner DateTime object with specified Day, Month and Year properties.
/// </summary>
public void UpdateInner()
{
if (Day.HasValue && Month.HasValue && Year.HasValue)
DateTime = new DateTime(Year.Value, Month.Value, Day.Value);
}
public override string ToString()
{
return DateTime.ToString();
}
[Range(1, 31, ErrorMessage = "Day number should be from 1 to 31.")]
public int? Day { get; set; }
[Range(1, 12, ErrorMessage = "Month number should be from 1 to 12.")]
public int? Month { get; set; }
[RangeCurrentYear(1900, ErrorMessage = "Year number should be from 1900 to current year.")]
public int? Year { get; set; }
}
Эта «оболочка» для DateTime используется в модели представления, имеющей следующий код:
public class ViewModel
{
...
public Date3 DateOfBirth3 { get; set; }
[Date3GreaterThanAnother("DateOfBirth3", "Date of death should be after date of birth.")]
public Date3 DateOfDeath3 { get; set; }
...
}
Класс атрибута проверки Date3GreaterThanAnother выглядит следующим образом (я пытался реализовать проверку на стороне клиента, поэтому он реализует интерфейс IClientValidatable):
[AttributeUsage(AttributeTargets.Property)]
public class Date3GreaterThanAnotherAttribute : ValidationAttribute, IClientValidatable
{
private readonly string _anotherProperty;
public Date3GreaterThanAnotherAttribute(string anotherDatePropertyName, string errorMessage = null)
{
_anotherProperty = anotherDatePropertyName;
if(errorMessage != null)
ErrorMessage = errorMessage;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var property = validationContext.ObjectType.GetProperty(_anotherProperty);
if (property == null)
return new ValidationResult($"Unknown property {_anotherProperty}", new string[] {_anotherProperty});
var otherDateValue = property.GetValue(validationContext.ObjectInstance, null);
if (!(otherDateValue is Date3 otherDate3))
return new ValidationResult($"Other property is not of Date3 type.");
var date3 = (Date3)value;
otherDate3.UpdateInner();
date3.UpdateInner();
if (otherDate3.DateTime >= date3.DateTime)
return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
return ValidationResult.Success;
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
var rule = new ModelClientValidationRule()
{
ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()),
ValidationType = "greaterthananotherdate"
};
rule.ValidationParameters.Add("otherdate", _anotherProperty);
yield return rule;
}
}
И, наконец, вот как я отображаю его на странице просмотра (удален несоответствующий код разметки):
...
@Html.LabelFor(x => x.Estate.DateOfBirth3.Day, "Date of Birth", new {@class = "control-label col-md-2 control-label-details"})
<div class="col-md-3">
@Html.EditorFor(x => x.Estate.DateOfBirth3.Day, new {htmlAttributes = new {@class = "form-control date3 day", placeholder = "DD"}})
@Html.ValidationMessageFor(x => x.Estate.DateOfBirth3.Day)
/
@Html.EditorFor(x => x.Estate.DateOfBirth3.Month, new {htmlAttributes = new {@class = "form-control date3 month", placeholder = "MM"}})
@Html.ValidationMessageFor(x => x.Estate.DateOfBirth3.Month)
/
@Html.EditorFor(x => x.Estate.DateOfBirth3.Year, new {htmlAttributes = new {@class = "form-control date3 year", placeholder = "YYYY"}})
@Html.ValidationMessageFor(x => x.Estate.DateOfBirth3.Year)
</div>
...
@Html.LabelFor(x => x.Estate.DateOfDeath3.Day, "Date of Death", new { @class = "control-label col-md-2 control-label-details" })
<div class="col-md-3">
@Html.EditorFor(x => x.Estate.DateOfDeath3.Day, new { htmlAttributes = new { @class = "form-control date3 day", placeholder = "DD" } })
@Html.ValidationMessageFor(x => x.Estate.DateOfDeath3.Day)
/
@Html.EditorFor(x => x.Estate.DateOfDeath3.Month, new { htmlAttributes = new { @class = "form-control date3 month", placeholder = "MM" } })
@Html.ValidationMessageFor(x => x.Estate.DateOfDeath3.Month)
/
@Html.EditorFor(x => x.Estate.DateOfDeath3.Year, new { htmlAttributes = new { @class = "form-control date3 year", placeholder = "YYYY" } })
@Html.ValidationMessageFor(x => x.Estate.DateOfDeath3.Year)
</div>
@Html.ValidationMessageFor(x => x.Estate.DateOfDeath3)
...
Если необходим код JS - я нашел решения для стекового потока в отношении ненавязчивой проверки JQuery, но не реализовал его, поскольку не могу запустить его из-за проблем, связанных с MVC.
Без использования DateOfDeath3 на странице просмотра ненавязчивая проверка не работает.
Я пытался добавить HiddenFor для DateOfDeath3, ненавязчивая проверка jquery начала работать, но в классе Date3GreaterThanAnother я обнаружил исключения для значение параметр = ноль.
$.validator.addMethod("greaterthananotherdate",
function (value, element, params) {
// TODO: implement validation logic.
console.log("validation method triggered");
return false;
}, 'ERROR');
$.validator.unobtrusive.adapters.add(
"greaterthananotherdate",
["otherdate"],
function (options) {
console.log("adapter triggered");
options.rules["greaterthananotherdate"] = "#" + options.params.otherdate;
options.messages["greaterthananotherdate"] = options.message;
});