为啥不显眼的验证直到 AJAX 发布之后才起作用?
Posted
技术标签:
【中文标题】为啥不显眼的验证直到 AJAX 发布之后才起作用?【英文标题】:Why doesn't unobtrusive validation work until after an AJAX post?为什么不显眼的验证直到 AJAX 发布之后才起作用? 【发布时间】:2013-10-08 01:54:37 【问题描述】:我有一个 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() 的结果,我看到我第一次点击保存时没有错误,但第二次(发布后)错误就在那里。
这可能是我想念的一些简单的东西,但我不知道还能在这里尝试什么,而且我的时间不多了。
这是我在这里的第一篇文章,所以如果我忽略了包含相关内容,请告诉我,我可以更新我的问题。
【问题讨论】:
【参考方案1】:我不确定它为什么第二次起作用,为了使客户端验证起作用,您需要通过返回 false 或在 saveClick()
中执行 e.preventDefault() 来防止提交表单方法。
【讨论】:
实际上,我认为我不需要阻止默认设置,因为我的保存按钮实际上是一个 你是对的。再次查看问题后,我想我看到了可能发生的情况,MVC3 将尝试使用 Ajax.BeginForm 将表单提交到服务器进行验证。我相信如果您使用 HTML.BeginForm 那么 jQuery 验证器将有机会启动并停止传统的表单提交。这可能是它第二次工作的原因,因为它可能知道不要尝试自己的 Ajax POST。让我知道这是否有效,我会发布一个新答案。以上是关于为啥不显眼的验证直到 AJAX 发布之后才起作用?的主要内容,如果未能解决你的问题,请参考以下文章
jquery datepicker上的自定义动态验证直到第二个焦点才起作用
为啥我的 C++ 函数只有放在 main() 之后才起作用?
jquery.validate.js第一次提交验证不起作用,刷新之后再提交才起作用,请各位帮忙看看是怎么回事!