我有一个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()的结果,我看到第一次单击Save时没有错误,但是第二次(在post之后)错误就在那里。
这可能是我想念的简单事情,但我不知道还有什么可以尝试,而且我已经没时间了。
这是我在这里的第一篇文章,所以如果我忽略了包含相关的内容,请告诉我,我可以更新我的问题。
答案 0 :(得分:0)
我不确定为什么它第二次工作,为了使客户端验证工作,你将希望通过返回false或在{{1中执行e.preventDefault()来阻止提交表单方法。