我有一个 View 模型,其中包含某人出生日期的年/月/日属性。所有这些字段都是必需的。现在,如果有人没有输入任何出生日期,他们会收到 3 条单独的错误消息。
我想做的是以某种方式将这些错误消息组合成一条消息,仅显示“需要出生日期”。因此,如果这些字段中的 1 个或多个字段为空白,它们将始终只收到 1 条验证消息。
我需要这个来通过 jquery validate 和 unobtrusive validate 进行客户端验证。通过查看此 question,我知道使用 jquery 验证插件是可能的.但我不知道如何使用 asp.net mvc 在我的模型上使用验证属性和不显眼的验证来实现这一点。希望有一些内置的方法可以出于验证目的对属性进行分组,但如果没有,可以使用自定义验证属性来完成吗?
这是我现有的模型和 View 的样子:
模型:
public class MyModel {
[Required(ErrorMessage = "Year is required")]
public int Year { get; set; }
[Required(ErrorMessage = "Month is required")]
public int Month { get; set; }
[Required(ErrorMessage = "Day is required")]
public int Day { get; set; }
}
View :
<div>
<label>Date of birth: <span style="color:red;">*</span></label>
<div>@Html.DropDownListFor(m => m.Year, ApplicationModel.GetSelectListForDateRange(DateTime.Today.Year - 16, DateTime.Today.Year - 10), "", new{data_description="birthDate"})@Html.LabelFor(m => m.StudentBirthYear)</div>
<div>@Html.DropDownListFor(m => m.Month, ApplicationModel.GetSelectListForDateRange(1, 12, true), "", new{data_description="birthDate"})@Html.LabelFor(m => m.StudentBirthMonth)</div>
<div>@Html.DropDownListFor(m => m.Day, ApplicationModel.GetSelectListForDateRange(1, 31), "", new{data_description="birthDate"})@Html.LabelFor(m => m.StudentBirthDay)</div>
</div>
<div class="error-container">@Html.ValidationMessageFor(m => m.Year)</div>
<div class="error-container">@Html.ValidationMessageFor(m => m.Month)</div>
<div class="error-container">@Html.ValidationMessageFor(m => m.Day)</div>
最佳答案
我参加聚会有点晚了(只有几年)仍然......
最合适的解决方案确实是创建一个 CustomAttribute
,但我不会给您很好的建议让您去死,我会告诉您如何做。
自定义属性:
public class GroupRequiredAttribute : ValidationAttribute, IClientValidatable
{
private readonly string[] _serverSideProperties;
public GroupRequiredAttribute(params string[] serverSideProperties)
{
_serverSideProperties = serverSideProperties;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
if (_serverSideProperties == null || _serverSideProperties.Length < 1)
{
return null;
}
foreach (var input in _serverSideProperties)
{
var propertyInfo = validationContext.ObjectType.GetProperty(input);
if (propertyInfo == null)
{
return new ValidationResult(string.Format("unknown property {0}", input));
}
var propertyValue = propertyInfo.GetValue(validationContext.ObjectInstance, null);
if (propertyValue is string && !string.IsNullOrEmpty(propertyValue as string))
{
return null;
}
if (propertyValue != null)
{
return null;
}
}
return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
var rule = new ModelClientValidationRule
{
ErrorMessage = ErrorMessage,
ValidationType = "grouprequired"
};
rule.ValidationParameters["grouprequiredinputs"] = string.Join(",", this._serverSideProperties);
yield return rule;
}
}
ViewModel:在您的 viewModel 上仅装饰一个字段,如下所示:
[GroupRequired("Year", "Month", "Day", ErrorMessage = "Please enter your date of birth")]
public int? Year { get; set; }
public int? Month { get; set; }
public int? Day { get; set; }
Jquery:您将需要添加适配器,在我的例子中它是 jquery.validate.unobtrusive.customadapters.js
或您注册适配器的任何地方(您可以将其放在页面只是在不显眼的验证运行后执行此操作)。
(function ($) {
jQuery.validator.unobtrusive.adapters.add('grouprequired', ['grouprequiredinputs'], function (options) {
options.rules['grouprequired'] = options.params;
options.messages['grouprequired'] = options.message;
});
}(jQuery));
jQuery.validator.addMethod('grouprequired', function (value, element, params) {
var inputs = params.grouprequiredinputs.split(',');
var values = $.map(inputs, function (input, index) {
var val = $('#' + input).val();
return val != '' ? input : null;
});
return values.length == inputs.length;
});
这样就可以了。
对于那些对它的作用感兴趣的人:在 C# 领域,它获取字段的 ID,将它们与 、
粘合在一起,然后放入 Year 字段的自定义属性中。
HTML 应该看起来像这样(如果它不调试 C# 属性):
<input class="tooltip form-control input dob--input-long" data-val="true" data-val-grouprequired="Please enter your date of birth" data-val-grouprequired-grouprequiredinputs="Year,Month,Day" name="Year" placeholder="YYYY" tabindex="" type="text" value="">
然后 Jquery 验证将它们拆分回 id,并检查它们是否都不为空,仅此而已。
你会想以某种方式将字段标记为无效(现在它只会标记字段属性)最合适的解决方案恕我直言是用类 field-error-wrapper
将所有字段包装在容器中然后在加载 Jquery 验证后将以下内容添加到您的页面:
$.validator.setDefaults({
highlight: function (element) {
$(element).closest(".field-error-wrapper").addClass("input-validation-error");
},
unhighlight: function (element) {
$(element).closest(".field-error-wrapper").removeClass("input-validation-error");
}
});
它不会标记字段,而是会标记容器,然后您可以以一种方式编写您的 css,如果容器标记有 .input-validation-error
,则其中的所有字段都会变为红色。我想我的工作已经完成了。
编辑: 好吧,似乎还有一个问题是字段未被标记,因为验证器认为日期和月份是有效的,它需要从父级中删除无效类,验证器首先标记无效字段,然后unmarks valid 这会导致验证不被突出显示,所以我更改了验证发生的顺序,我不建议全局覆盖它(因为我不确定它可能有什么灾难性的影响)只需将它粘贴到页面上你有生日字段。
$(function () {
$.data($('form')[0], 'validator').settings.showErrors = function () {
if (this.settings.unhighlight) {
for (var i = 0, elements = this.validElements() ; elements[i]; i++) {
this.settings.unhighlight.call(this, elements[i], this.settings.errorClass, this.settings.validClass);
}
}
this.hideErrors();
for (var i = 0; this.errorList[i]; i++) {
var error = this.errorList[i];
this.settings.highlight && this.settings.highlight.call(this, error.element, this.settings.errorClass, this.settings.validClass);
this.showLabel(error.element, error.message);
}
if (this.errorList.length) {
this.toShow = this.toShow.add(this.containers);
}
if (this.settings.success) {
for (var i = 0; this.successList[i]; i++) {
this.showLabel(this.successList[i]);
}
}
this.toHide = this.toHide.not(this.toShow);
this.addWrapper(this.toShow).show();
};
});
希望这能为您节省一些时间。
关于c# - 将多个属性的验证消息组合到一条消息中 asp.net mvc,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18725417/