草庐IT

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

coder 2024-05-23 原文

我有一个 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/

有关c# - 将多个属性的验证消息组合到一条消息中 asp.net mvc的更多相关文章

  1. ruby-on-rails - Rails 3 中的多个路由文件 - 2

    Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题

  2. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  3. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

    我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

  4. ruby-on-rails - 在 Ruby 中循环遍历多个数组 - 2

    我有多个ActiveRecord子类Item的实例数组,我需要根据最早的事件循环打印。在这种情况下,我需要打印付款和维护日期,如下所示:ItemAmaintenancerequiredin5daysItemBpaymentrequiredin6daysItemApaymentrequiredin7daysItemBmaintenancerequiredin8days我目前有两个查询,用于查找maintenance和payment项目(非排他性查询),并输出如下内容:paymentrequiredin...maintenancerequiredin...有什么方法可以改善上述(丑陋的)代

  5. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

    我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

  6. ruby-on-rails - 如果为空或不验证数值,则使属性默认为 0 - 2

    我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val

  7. ruby-on-rails - 在混合/模块中覆盖模型的属性访问器 - 2

    我有一个包含模块的模型。我想在模块中覆盖模型的访问器方法。例如:classBlah这显然行不通。有什么想法可以实现吗? 最佳答案 您的代码看起来是正确的。我们正在毫无困难地使用这个确切的模式。如果我没记错的话,Rails使用#method_missing作为属性setter,因此您的模块将优先,阻止ActiveRecord的setter。如果您正在使用ActiveSupport::Concern(参见thisblogpost),那么您的实例方法需要进入一个特殊的模块:classBlah

  8. ruby-on-rails - 如何验证非模型(甚至非对象)字段 - 2

    我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss

  9. ruby - 多个属性的 update_column 方法 - 2

    我有一个具有一些属性的模型:attr1、attr2和attr3。我需要在不执行回调和验证的情况下更新此属性。我找到了update_column方法,但我想同时更新三个属性。我需要这样的东西:update_columns({attr1:val1,attr2:val2,attr3:val3})代替update_column(attr1,val1)update_column(attr2,val2)update_column(attr3,val3) 最佳答案 您可以使用update_columns(attr1:val1,attr2:val2

  10. ruby-on-rails - 在 ruby​​ .gemspec 文件中,如何指定依赖项的多个版本? - 2

    我正在尝试修改当前依赖于定义为activeresource的gem:s.add_dependency"activeresource","~>3.0"为了让gem与Rails4一起工作,我需要扩展依赖关系以与activeresource的版本3或4一起工作。我不想简单地添加以下内容,因为它可能会在以后引起问题:s.add_dependency"activeresource",">=3.0"有没有办法指定可接受版本的列表?~>3.0还是~>4.0? 最佳答案 根据thedocumentation,如果你想要3到4之间的所有版本,你可以这

随机推荐