c# - 将多个属性的验证消息组合到一条消息中 asp.net mvc

标签 c# asp.net-mvc asp.net-mvc-4 jquery-validate unobtrusive-validation

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

Date of birth fields

我想做的是以某种方式将这些错误消息组合成一条消息,仅显示“需要出生日期”。因此,如果这些字段中的 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/

相关文章:

C#正则表达式提取一个div的内容

C# 切换/中断

javascript - 如何将复选框添加到 Kendo Grid 的工具栏?

.net - 通过 .NET MVC 4 中的第三个实体关联两个实体

c# - 使用 INSERT...RETURNING 子句导致 ORA-12537

c# - 如何在列表框中显示文件名但使用 openfiledialog 保留相对路径?

asp.net-mvc - 使用基本身份验证模拟 Azure 调度程序

asp.net-mvc - 有人在实时站点上使用 ASP.NET MVC 框架吗?

jquery - 将 JQuery 插件添加到新的 MVC4 Web 应用程序

asp.net-mvc-4 - 将 Expression<Func<TModel, TValue>> 转换为 Expression<Func<TModel, bool>>