2

我正在尝试使用创建自定义验证IClientValidatable

我有 2 个字段 PhoneNumber 和 Mobile。我希望用户选择其中一个或两个。只需要 1 个,但必须至少提供 1 个。

到目前为止,我已经设法做到了

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


        rule.ValidationParameters.Add("phone", "PhoneNumber");
        rule.ValidationParameters.Add("mobile", "MobileNumber");

        yield return rule;
    }

这会将验证应用于输出的 html 元素

<input data-val="true" data-val-length="Mobile number must be a maximum length of 14." data-val-length-max="14" data-val-required="Landline or mobile phone number is needed." data-val-required-required="MobileNumber" id="MobileNumber" name="MobileNumber" type="text" value="">
<input data-val="true" data-val-length="Landline number must be a maximum length of 14." data-val-length-max="14" data-val-required="Landline or mobile phone number is needed." data-val-required-required="PhoneNumber" id="PhoneNumber" name="PhoneNumber" type="text" value="">

现在我知道这还没有完成。但是如果我尝试点击提交按钮,验证会在我的摘要中显示 2 个验证错误。

我对如何添加验证器适配器有点困惑。

到目前为止....任何我知道它错了但是

 jQuery.validator.unobtrusive.adapters.add('required',
        [$("#PhoneNumber").val(), $("#MobileNumber").val()],
        function(options) {
                    options.rules['required'] = options.params;
                    options.messages['required'] = options.message;
        });
4

1 回答 1

1

首先,您需要以与比较属性类似的方式创建自己的验证属性。

在此属性中,您将指定其他依赖属性,错误消息的格式将考虑属性显示名称。

该属性看起来像这样(我对它的名称和默认错误消息不太自豪!):

public class SelectOneValidationAttribute : ValidationAttribute, IClientValidatable
{
    private const string DefaultErrorMessage = "Please enter '{0}' or '{1}'.";
    private string _otherFieldName;

    public SelectOneValidationAttribute(String otherFieldName)
        : base(DefaultErrorMessage)
    {
        _otherFieldName = otherFieldName;
    }

    public override string FormatErrorMessage(string name)
    {
        return String.Format(CultureInfo.CurrentCulture, ErrorMessageString, name, _otherFieldName);
    }

    protected override DataAnnotationsValidationResult IsValid(object value, ValidationContext validationContext)
    {
        PropertyInfo otherPropertyInfo = validationContext.ObjectType.GetProperty(_otherFieldName);
        if (otherPropertyInfo == null)
        {
            return new DataAnnotationsValidationResult("Unknown property " + _otherFieldName);
        }


        string strValue = value == null ? null : value.ToString();
        if(!String.IsNullOrEmpty(strValue))
            //validation succeeds as this field has been populated
            return null;

        object otherPropertyValue = otherPropertyInfo.GetValue(validationContext.ObjectInstance, null);

        string strOtherPropertyValue = otherPropertyValue == null ? null : otherPropertyValue.ToString();
        if (!String.IsNullOrEmpty(strOtherPropertyValue))
            //validation succeeds as the other field has been populated
            return null; 
        else
            //validation failed, none of the 2 fields were populated
            return new DataAnnotationsValidationResult(DefaultErrorMessage);
    }


    //Create the data attributes for the client to use
    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        var rule = new ModelClientValidationRule
        {
            ValidationType = "selectone",
            ErrorMessage = FormatErrorMessage(metadata.GetDisplayName())
        };

        rule.ValidationParameters["otherfield"] = FormatPropertyForClientValidation(_otherFieldName);

        yield return rule;
    }

    public static string FormatPropertyForClientValidation(string property)
    {
        return "*." + property;
    }
}

因此,您可以在模型中使用它,如下所示:

public class YourModel
{
    [SelectOneValidation("Phone")]
    public string Mobile { get; set; }

    [SelectOneValidation("Mobile")]
    public string Phone { get; set; }
}

使用该代码,错误消息“请输入‘手机’或‘电话’。” 和“请输入‘电话’或‘手机’。” 将在服务器端验证失败时显示。(您可以在两者上设置相同的错误消息,例如“请输入...”)

为了添加客户端验证,您需要为不显眼的验证创建适配器。(确保在不显眼的验证解析文档之前将其添加到某处,否则您将需要手动解析它):

//Add an adaptor for our new jquery validator, that builds the optional parameters 
//for our validation code (the other field to look at)
$.validator.unobtrusive.adapters.add("selectone", ["otherfield"], function (options) {
    var prefix = getModelPrefix(options.element.name),
        other = options.params.otherfield,
        fullOtherName = appendModelPrefix(other, prefix),
        element = $(options.form).find(":input[name=" + fullOtherName + "]")[0];

    setValidationValues(options, "selectone", element);
});

这是使用在不显眼的验证库中定义的一些实用程序函数,例如:

function setValidationValues(options, ruleName, value) {
    options.rules[ruleName] = value;
    if (options.message) {
        options.messages[ruleName] = options.message;
    }
}

function getModelPrefix(fieldName) {
    return fieldName.substr(0, fieldName.lastIndexOf(".") + 1);
}

function appendModelPrefix(value, prefix) {
    if (value.indexOf("*.") === 0) {
        value = value.replace("*.", prefix);
    }
    return value;
}

最后我创建了一个新的验证规则。这是因为尽管所需的验证允许设置过滤表达式,因此该字段仅在该表达式被评估为 true 时才被标记为有效,请参阅required validation,我们需要对 onBlur 验证应用与 equalto 规则类似的修复。

验证方法是从 equalto 验证中应用上述修复,然后仅在其他相关字段上使用依赖选择器调用所需规则,因此仅当字段为空且依赖项尚未填充时,所需验证才返回 false。

$.validator.addMethod("selectone", function (value, element, param) {
    // bind to the blur event of the target in order to revalidate whenever the target field is updated
    // TODO find a way to bind the event just once, avoiding the unbind-rebind overhead
    var otherField = $(param);
    if (this.settings.onfocusout) {
        otherField.unbind(".validate-selectone").bind("blur.validate-selectone", function () {
            $(element).valid();
        });
    }

    var otherFieldBlankFilter = ":input[name=" + otherField[0].name + "]:blank";
    return $.validator.methods.required.call(this, value, element, otherFieldBlankFilter);
});

如果您不介意这一点,就好像您仅在提交表单时进行验证,您可以编写一个直接使用所需规则的适配器:

$.validator.unobtrusive.adapters.add("selectone", ["otherfield"], function (options) {
    var prefix = getModelPrefix(options.element.name),
        other = options.params.otherfield,
        fullOtherName = appendModelPrefix(other, prefix),
        element = $(options.form).find(":input[name=" + fullOtherName + "]")[0];

    setValidationValues(options, "required", ":input[name=" + fullOtherName + "]:blank");
});

有了所有这些,您的验证应该可以工作。如果两者都是空的并且您尝试提交,则会为这两个字段显示错误消息。如果您随后在其中一个中输入内容并标记出来,则应删除两条错误消息。

您还应该能够根据自己的需要进行调整,因为您可以修改验证属性、不显眼的适配器和验证规则。

于 2012-12-08T13:05:12.027 回答