MVC3 自定义不引人注目的验证 - 从复选框强制验证

发布于 2024-12-01 13:53:32 字数 2571 浏览 4 评论 0原文

我有以下用于自定义验证的类:

[AttributeUsage(AttributeTargets.Property, AllowMultiple=false, Inherited=true)]
public sealed class RequiredIfAnyTrueAttribute : ValidationAttribute, IClientValidatable
{
    private const string DefaultErrorMessage = "{0} is required";

    public List<string> OtherProperties { get; private set; }

    public RequiredIfAnyTrueAttribute(string otherProperties)
        : base(DefaultErrorMessage)
    {
        if (string.IsNullOrEmpty(otherProperties))
            throw new ArgumentNullException("otherProperty");

        OtherProperties = new List<string>(otherProperties.Split(new char[] { '|', ',' }));
    }

    public override string FormatErrorMessage(string name)
    {
        return string.Format(ErrorMessageString, name);
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        if (value == null)
        {
            foreach (string s in OtherProperties)
            {
                var otherProperty = validationContext.ObjectType.GetProperty(s);
                var otherPropertyValue = otherProperty.GetValue(validationContext.ObjectInstance, null);

                if (otherPropertyValue.Equals(true))
                    return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
            }
        }

        return ValidationResult.Success;
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        var clientValidationRule = new ModelClientValidationRule()
        {
            ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()),
            ValidationType = "requiredifanytrue"
        };

        clientValidationRule.ValidationParameters.Add("otherproperties", string.Join("|",OtherProperties));

        return new[] { clientValidationRule };
    }
}

我的 ViewModel 是:

public class SampleViewModel
{
    public bool PropABC { get; set; }
    public bool PropXYZ { get; set; }

    [RequiredIfAnyTrue("PropABC|PropXYZ")]
    public int? TestField { get; set; }
}

当我的强类型视图呈现时,一切看起来都工作正常。如果选择 PropABC 或 PropXYZ,那么我需要输入 TestField 的值。客户端和服务器端验证均有效。

但是,给定以下事件顺序:

  1. 选中 PropABC
  2. 提交表单
  3. 客户端验证会触发需要的 TestField
  4. 取消选中 PropABC
  5. 客户端验证不会重新触发并且验证消息 保持直到表单提交

为了解决#5,我通常会通过 jquery onready 将单击事件附加到复选框以重新触发验证。

在给定 MVC3 + unobtrusive + jquery 的情况下,是否有首选/推荐的方法来手动强制客户端验证?

I have the following class used for custom validation:

[AttributeUsage(AttributeTargets.Property, AllowMultiple=false, Inherited=true)]
public sealed class RequiredIfAnyTrueAttribute : ValidationAttribute, IClientValidatable
{
    private const string DefaultErrorMessage = "{0} is required";

    public List<string> OtherProperties { get; private set; }

    public RequiredIfAnyTrueAttribute(string otherProperties)
        : base(DefaultErrorMessage)
    {
        if (string.IsNullOrEmpty(otherProperties))
            throw new ArgumentNullException("otherProperty");

        OtherProperties = new List<string>(otherProperties.Split(new char[] { '|', ',' }));
    }

    public override string FormatErrorMessage(string name)
    {
        return string.Format(ErrorMessageString, name);
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        if (value == null)
        {
            foreach (string s in OtherProperties)
            {
                var otherProperty = validationContext.ObjectType.GetProperty(s);
                var otherPropertyValue = otherProperty.GetValue(validationContext.ObjectInstance, null);

                if (otherPropertyValue.Equals(true))
                    return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
            }
        }

        return ValidationResult.Success;
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        var clientValidationRule = new ModelClientValidationRule()
        {
            ErrorMessage = FormatErrorMessage(metadata.GetDisplayName()),
            ValidationType = "requiredifanytrue"
        };

        clientValidationRule.ValidationParameters.Add("otherproperties", string.Join("|",OtherProperties));

        return new[] { clientValidationRule };
    }
}

My ViewModel is:

public class SampleViewModel
{
    public bool PropABC { get; set; }
    public bool PropXYZ { get; set; }

    [RequiredIfAnyTrue("PropABC|PropXYZ")]
    public int? TestField { get; set; }
}

When my strongly typed view renders, everything sees to work fine. If PropABC or PropXYZ is selected then I am required to enter a value for TestField. Both client and server-side validation is functional.

However, given the following sequence of events:

  1. check PropABC
  2. submit form
  3. client-side validation fires for TestField required
  4. uncheck PropABC
  5. client validation does not re-fire and validation message
    remains until form submit

In order to resolve #5 I would typically attach click events to the checkboxes via jquery onready to refire the validation.

Is there a preferred/recommended way to manually force client-side validation given MVC3 + unobstrusive + jquery?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

岁月无声 2024-12-08 13:53:32

Shawn,附加到事件是获得重新触发验证的最佳方法。

我建议创建一个名为“validate”的类(或类似的类),将其添加到要验证的每个元素,然后使用 jQuery 附加到每个元素的单击和模糊事件(可能还有更改事件)该类,并像这样验证元素:

$("form").validate().element(this);

Shawn, attaching to events is the best approach to get validation to refire.

I would suggest creating a class called "validate" (or something along those lines), adding it to each element to be validated, and then use jQuery to attach to the click and blur events (and possibly the change event) of each element with that class, and validate the element like so:

$("form").validate().element(this);
聆听风音 2024-12-08 13:53:32

需要自己写属性吗?如果不是,我认为你也许能​​够避免“重新发明轮子”

FoolProof 效果很好。您可以将其作为 NuGet 包获取。

NuGet:安装包万无一失

它包含许多用于动态必需字段等的各种组合的重要属性。

Do you need to write your own attributes? If not I think you may be able to avoid "reinventing the wheel"

FoolProof works great. you get get it as a NuGet package.

NuGet: install-package foolproof

It includes a lot of greate attributes for various combinations of on-the-fly required fields and such.

够运 2024-12-08 13:53:32

FoolProof 仍处于测试阶段,不适用于嵌套视图模型,也不适用于数组

FoolProof is still in beta and does not work with nested viewmodel, also with arrays

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文