将多个属性的验证消息组合在一起成为一个消息asp.net mvc

bba*_*bak 13 c# asp.net-mvc jquery-validate unobtrusive-validation asp.net-mvc-4

我有一个视图模型,其中包含某人出生日期的年/月/日属性.所有这些字段都是必需的.现在,如果有人在出生日期没有输入任何内容,则会收到3条单独的错误消息.

出生日期字段

我想要做的是以某种方式将这些错误消息组合成一条消息,该消息只是说"出生日期是必需的".因此,如果这些字段中的一个或多个是空白的,它们将始终只获得1个验证消息.

我需要通过jquery验证和不引人注意的验证来处理客户端验证.我知道通过查看这个问题可以使用jquery validate插件.但是我不知道如何使用我的模型上的验证属性和不显眼的验证来使用asp.net mvc来实现这一点.希望有一些内置的方法可以将属性分组以进行验证,但如果没有,可以使用自定义验证属性吗?

这是我现有的模型和视图的样子:

该模型:

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; }
}
Run Code Online (Sandbox Code Playgroud)

风景:

<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>
Run Code Online (Sandbox Code Playgroud)

Mat*_*ius 8

我有点迟到了(只有几年)...

最合适的解决方案确实创造了一个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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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; }
Run Code Online (Sandbox Code Playgroud)

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;
});
Run Code Online (Sandbox Code Playgroud)

那应该这样做.

对于那些感兴趣的人:在C#land中,它抓取字段的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="">
Run Code Online (Sandbox Code Playgroud)

然后Jquery验证将它们分解为id并检查它们是否都是空的,这就是它.

您将希望以某种方式将字段标记为无效(现在它只标记字段属性正在处理)最合适的解决方案IMHO将使用类包装容器中的所有字段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");
    }
});
Run Code Online (Sandbox Code Playgroud)

而不是标记字段,它将标记容器,然后您可以编写您的CSS,如果容器被标记,.input-validation-error然后内部的所有字段变为红色.我认为我的工作已经完成.

编辑:好的所以似乎还有一个问题,其中字段被取消标记,因为验证器认为日期和月份有效并且需要从父级删除无效的类,验证器首先标记无效字段然后取消标记有效,导致验证不被突出显示,所以我改变了验证发生的顺序,我不建议全局覆盖它(因为我不确定它可能有什么灾难性的影响)只是将它粘贴在你有生日字段的页面上.

$(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();
    };
});
Run Code Online (Sandbox Code Playgroud)

希望这能为您节省一些时间.