jquery - 为什么不引人注目的验证只有在 AJAX 发布之后才起作用?

标签 jquery ajax asp.net-mvc-3 validation

我有一个 MVC3 项目,其中我想使用自定义验证属性进行客户端和服务器端处理。我已按照http://thewayofcode.wordpress.com/2012/01/18/custom-unobtrusive-jquery-validation-with-data-annotations-in-mvc-3/中找到的步骤进行操作。这是一个很棒的教程,而且实际上效果很好。

我遇到的唯一问题是,在提交表单之后之前,我的验证似乎不会触发。我有客户端和服务器端验证。服务器端验证是验证属性和自定义验证的组合(例如,有时我必须根据数据库中的某些内容检查输入值)。当我第一次单击表单上的“保存”按钮(使用 Ajax.BeginForm)时,该帖子发生在服务器上,服务器端验证启动并返回验证消息,因为输入无效。如果我将表单输入保持原样,然后再次单击“保存”按钮,客户端验证将正常工作并阻止发布。

什么可能导致客户端验证被跳过,直到表单发布之后?

我的自定义验证属性:

    public class RequiredIfContainsAttribute : ValidationAttribute, IClientValidatable
    {
        private RequiredAttribute _innerAttribute = new RequiredAttribute();

        public string DependentProperty { get; set; }
        public string ComparisonValue { get; set; }

        public RequiredIfContainsAttribute(string dependentProperty, string comparisonValue)
        {
            DependentProperty = dependentProperty;
            ComparisonValue = comparisonValue;
        }

        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            // get a reference to the property this validation depends upon
            var containerType = validationContext.ObjectInstance.GetType();
            var field = containerType.GetProperty(DependentProperty);

            if (field != null)
            {
                // get the value of the dependent property
                var dependentValue = field.GetValue(validationContext.ObjectInstance, null);

                // this validation only works if the comparison field is a string
                if (dependentValue.GetType() != typeof(string))
                {
                    return ValidationResult.Success;
                }

                var dependentString = (string) dependentValue;

                // check whether the string to check contains the comparison value
                if (dependentString.Contains(ComparisonValue))
                {
                    // if the string to check contains the comparison value, the attribute becomes required and must now be validated
                    if (!_innerAttribute.IsValid(value))
                    {
                        // validation failed - return an error
                        return new ValidationResult(ErrorMessage, new[] {validationContext.MemberName});
                    }
                }
            }

            return ValidationResult.Success;
        }

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

            var depProp = BuildDependentPropertyId(metadata, context as ViewContext);

            rule.ValidationParameters.Add("dependentproperty", depProp);
            rule.ValidationParameters.Add("comparisonvalue", ComparisonValue);

            yield return rule;
        }

        private string BuildDependentPropertyId(ModelMetadata metadata, ViewContext viewContext)
        {
            string depProp = viewContext.ViewData.TemplateInfo.GetFullHtmlFieldId(DependentProperty);

            var thisField = metadata.PropertyName + "_";
            if (depProp.StartsWith(thisField))
            {
                // strip it off again
                depProp = depProp.Substring(thisField.Length);
            }

            return depProp;
        }
    }

我的模型属性:

    [RequiredIfContains("FirstName", "Mickey", ErrorMessage = "The date of birth is required when the first name is Mickey")]
    public DateTime DateOfBirth { get; set; }

我的自定义 js 添加验证器:

$.validator.addMethod('requiredifcontains',
function (value, element, parameters) {
    console.log("requiredifcontains starting");
    var id = '#' + parameters['dependentproperty'];

    // get the target value (as a string, 
    // as that's what actual value will be)
    var comparisonvalue = parameters['comparisonvalue'];
    comparisonvalue =
      (comparisonvalue == null ? '' : comparisonvalue).toString();

    // get the actual value of the target control
    // note - this probably needs to cater for more 
    // control types, e.g. radios
    var control = $(id);
    var inputValue = 'empty';
    if (control.is('input:text')) {
        inputValue = control.text();
    } else if (control.is('select')) {
        inputValue = $(id + " option:selected").text();
    }

    // if the input control wasn't found (possibly because the type wasn't checked for) then we can't compare so just return true
    if (inputValue == 'empty') {
        return true;
    }

    // if the condition is true, reuse the existing 
    // required field validator functionality
    console.log("requiredifcontains performing underlying validation");
    if (inputValue.indexOf(comparisonvalue) > -1)
        return $.validator.methods.required.call(
          this, value, element, parameters);

    console.log("requiredifcontains returning true");
    return true;
}
);

$.validator.unobtrusive.adapters.add(
'requiredifcontains',
['dependentproperty', 'comparisonvalue'],
function (options) {
    options.rules['requiredifcontains'] = {
        dependentproperty: options.params['dependentproperty'],
        targetvalue: options.params['comparisonvalue']
    };
    options.messages['requiredifcontains'] = options.message;
});

一种与失败的观点几乎相同的人为观点:

@{
var options = new AjaxOptions()
    {
        HttpMethod = "Post",
        UpdateTargetId = "personalInfoDiv",
        OnSuccess = "FormSubmitSuccess()"
    };
}

<div id="personalInfoDiv">
@using (Ajax.BeginForm("PersonalInformationDetail", "PersonalInformation", null, options, new {@style = "height:100%", @id = "PersonalInformationForm"}))
{
    @Html.ValidationSummary(false)
    @Html.EditorForModel()
    <div style="float:left; position:relative;">
        <input type="button" value="Save" style="width:125px;" id="Save" onclick="saveClick(this)" />
    </div>
}
</div>

保存点击的 JavaScript 和成功方法:

function saveClick(e) {
var firstName = $("#FirstName").val();
var result = true;
if (firstName == '') {
    result = confirm("First name is not required but is recommended.  Choose OK to save anyway or CANCEL to add a first name.");
}

if (result) {
    $("#PersonalInformationForm").submit();
}
}

function FormSubmitSuccess(result) {
// do some stuff after the form submits
}

我已经寻找这个问题有一段时间了,我找到的大多数解决方案都是与我的问题相反的解决方案。我已经记录了 form.validate() 的结果,我发现第一次单击“保存”时没有错误,但第二次(发布后)出现错误。

这可能是我错过的一些简单的事情,但我不知道这里还能尝试什么,而且我已经没有时间了。

这是我在这里发表的第一篇文章,因此如果我忽略了相关内容,请告诉我,我可以更新我的问题。

最佳答案

我不太确定为什么它第二次起作用,为了让客户端验证起作用,您需要通过返回 false 或在 中执行 e.preventDefault() 来阻止提交表单saveClick() 方法。

关于jquery - 为什么不引人注目的验证只有在 AJAX 发布之后才起作用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19124092/

相关文章:

Jquery 动画圆形导航

javascript - 输入字段 : limit the number of letters and numbers typed

javascript - 如何按值将数据传递到延迟 then 处理程序?

c# - CaSTLe.Windsor 生活方式取决于上下文?

javascript - 在javascript中循环动态对象

asp.net - 使用 Jquery.post 时如何在 ASP.Net 中获取表单值

python - Gmail 是如何做到的?

PHP同步进程

security - 将用户名/密码存储在 session 状态中以便进行一次性 Pin 登录是否安全?

c# - 确定 View 是否被渲染为 Partial