我在MVC 2中使用jquery.validate和MicrosoftMvcJQueryValidation。我的模型上有数据注释,然后将其转换为jquery验证器。我正在使用对MicrosoftMvcJQueryValidation的修改,如国有企业屯所概述的那样,允许我的错误消息出现在验证摘要中,而不是在控件旁边。
当页面加载时,一切都按预期工作。问题是,我正在使用ajax表单和替换模式重写表单。当我这样做的时候,我失去了所有的客户端验证。
验证仍然发生在服务器端,出现错误的字段被正确地分配给css类以更改它们的样式。但是,我的验证摘要中只显示了最后一个错误消息。
控制器没什么特别的。如果模型有效,请执行操作,否则将同一模型返回到视图中。
这里是我的ajax表单的示例
<% using (Ajax.BeginForm("AddCreditCard", "Dashboard",
new { },
new AjaxOptions() {
HttpMethod = "Post",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "quickpay-wrapper",
OnSuccess = "newPaymentSetup",
LoadingElementId = "loading-pane"
}, new { id="new-credit-card-form" })) { %>以下是修改后的javascript。
jQuery.validator.addMethod("regex", function(value, element, params) {
if (this.optional(element)) {
return true;
}
var match = new RegExp(params).exec(value);
return (match && (match.index == 0) && (match[0].length == value.length));
});
// glue
function __MVC_ApplyValidator_Range(object, min, max) {
object["range"] = [min, max];
}
function __MVC_ApplyValidator_RegularExpression(object, pattern) {
object["regex"] = pattern;
}
function __MVC_ApplyValidator_Required(object) {
object["required"] = true;
}
function __MVC_ApplyValidator_StringLength(object, maxLength) {
object["maxlength"] = maxLength;
}
function __MVC_ApplyValidator_Unknown(object, validationType, validationParameters) {
object[validationType] = validationParameters;
}
function __MVC_CreateFieldToValidationMessageMapping(validationFields) {
var mapping = {};
for (var i = 0; i < validationFields.length; i++) {
var thisField = validationFields[i];
mapping[thisField.FieldName] = "#" + thisField.ValidationMessageId;
}
return mapping;
}
function __MVC_CreateErrorMessagesObject(validationFields) {
var messagesObj = {};
for (var i = 0; i < validationFields.length; i++) {
var thisField = validationFields[i];
var thisFieldMessages = {};
messagesObj[thisField.FieldName] = thisFieldMessages;
var validationRules = thisField.ValidationRules;
for (var j = 0; j < validationRules.length; j++) {
var thisRule = validationRules[j];
if (thisRule.ErrorMessage) {
var jQueryValidationType = thisRule.ValidationType;
switch (thisRule.ValidationType) {
case "regularExpression":
jQueryValidationType = "regex";
break;
case "stringLength":
jQueryValidationType = "maxlength";
break;
}
thisFieldMessages[jQueryValidationType] = thisRule.ErrorMessage;
}
}
}
return messagesObj;
}
function __MVC_CreateRulesForField(validationField) {
var validationRules = validationField.ValidationRules;
// hook each rule into jquery
var rulesObj = {};
for (var i = 0; i < validationRules.length; i++) {
var thisRule = validationRules[i];
switch (thisRule.ValidationType) {
case "range":
__MVC_ApplyValidator_Range(rulesObj,
thisRule.ValidationParameters["minimum"], thisRule.ValidationParameters["maximum"]);
break;
case "regularExpression":
__MVC_ApplyValidator_RegularExpression(rulesObj,
thisRule.ValidationParameters["pattern"]);
break;
case "required":
var fieldName = validationField.FieldName.replace(".", "_");
if ($("#" + fieldName).get(0).type !== 'checkbox') {
// only apply required if the input control is NOT a checkbox.
__MVC_ApplyValidator_Required(rulesObj);
}
break;
case "stringLength":
__MVC_ApplyValidator_StringLength(rulesObj,
thisRule.ValidationParameters["maximumLength"]);
break;
default:
__MVC_ApplyValidator_Unknown(rulesObj,
thisRule.ValidationType, thisRule.ValidationParameters);
break;
}
}
return rulesObj;
}
function __MVC_CreateValidationOptions(validationFields) {
var rulesObj = {};
for (var i = 0; i < validationFields.length; i++) {
var validationField = validationFields[i];
var fieldName = validationField.FieldName;
rulesObj[fieldName] = __MVC_CreateRulesForField(validationField);
}
return rulesObj;
}
function __MVC_EnableClientValidation(validationContext) {
// this represents the form containing elements to be validated
var theForm = $("#" + validationContext.FormId);
var fields = validationContext.Fields;
var rulesObj = __MVC_CreateValidationOptions(fields);
var fieldToMessageMappings = __MVC_CreateFieldToValidationMessageMapping(fields);
var errorMessagesObj = __MVC_CreateErrorMessagesObject(fields);
var options = {
errorClass: "input-validation-error",
errorElement: "span",
errorPlacement: function(error, element) {
var messageSpan = fieldToMessageMappings[element.attr("name")];
$(messageSpan).empty();
$(messageSpan).removeClass("field-validation-valid");
$(messageSpan).addClass("field-validation-error");
error.removeClass("input-validation-error");
error.attr("_for_validation_message", messageSpan);
error.appendTo(messageSpan);
},
messages: errorMessagesObj,
rules: rulesObj,
success: function(label) {
var messageSpan = $(label.attr("_for_validation_message"));
$(messageSpan).empty();
$(messageSpan).addClass("field-validation-valid");
$(messageSpan).removeClass("field-validation-error");
}
};
var validationSummaryId = validationContext.ValidationSummaryId;
if (validationSummaryId) {
// insert an empty <ul> into the validation summary <div> tag (as necessary)
$("<ul />").appendTo($("#" + validationSummaryId + ":not(:has(ul:first))"));
options = {
errorContainer: "#" + validationSummaryId,
errorLabelContainer: "#" + validationSummaryId + " ul:first",
wrapper: "li",
showErrors: function(errorMap, errorList) {
var errContainer = $(this.settings.errorContainer);
var errLabelContainer = $("ul:first", errContainer);
// Add error CSS class to user-input controls with errors
for (var i = 0; this.errorList[i]; i++) {
var element = this.errorList[i].element;
var messageSpan = $(fieldToMessageMappings[element.name]);
var msgSpanHtml = messageSpan.html();
if (!msgSpanHtml || msgSpanHtml.length == 0) {
// Don't override the existing Validation Message.
// Only if it is empty, set it to an asterisk.
//messageSpan.html("*");
}
messageSpan.removeClass("field-validation-valid").addClass("field-validation-error");
$("#" + element.id).addClass("input-validation-error");
}
for (var i = 0; this.successList[i]; i++) {
// Remove error CSS class from user-input controls with zero validation errors
var element = this.successList[i];
var messageSpan = fieldToMessageMappings[element.name];
$(messageSpan).addClass("field-validation-valid").removeClass("field-validation-error");
$("#" + element.id).removeClass("input-validation-error");
}
if (this.numberOfInvalids() > 0) {
errContainer.removeClass("validation-summary-valid").addClass("validation-summary-errors");
}
this.defaultShowErrors();
// when server-side errors still exist in the Validation Summary, don't hide it
var totalErrorCount = errLabelContainer.children("li:not(:has(label))").length + this.numberOfInvalids();
if (totalErrorCount > 0) {
$(this.settings.errorContainer).css("display", "block").addClass("validation-summary-errors").removeClass("validation-summary-valid");
$(this.settings.errorLabelContainer).css("display", "block");
}
},
messages: errorMessagesObj,
rules: rulesObj
};
}
// register callbacks with our AJAX system
var formElement = document.getElementById(validationContext.FormId);
var registeredValidatorCallbacks = formElement.validationCallbacks;
if (!registeredValidatorCallbacks) {
registeredValidatorCallbacks = [];
formElement.validationCallbacks = registeredValidatorCallbacks;
}
registeredValidatorCallbacks.push(function() {
theForm.validate();
return theForm.valid();
});
theForm.validate(options);
}
// need to wait for the document to signal that it is ready
$(document).ready(function() {
var allFormOptions = window.mvcClientValidationMetadata;
if (allFormOptions) {
while (allFormOptions.length > 0) {
var thisFormOptions = allFormOptions.pop();
__MVC_EnableClientValidation(thisFormOptions);
}
}
}); 我尝试将文档底部的调用移动到我的OnSuccess方法中,但这并没有做到。
因此,在执行ajax替换时,如何使客户端验证重新初始化,以及如何在验证摘要中显示所有错误?我希望如果我解决一个问题,它将纠正另一个问题。
编辑:
这里有一些关于我在做什么的更多信息
这是包装
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<QuickPayModel>" %>
<div id="quickpay-wrapper">
<% if (Model.NewPaymentMethod) { %>
<% Html.RenderAction<DashboardController>(x => x.QuickPayNewMethod()); %>
<% } else { %>
<% Html.RenderPartial("QuickPayMakePayment", Model); %>
<% } %>
</div>这是付款面板。
<%= Html.ClientValidationSummary(new { id = "valSumContainer" })%>
<% Html.EnableClientValidation(); %>
<% using (Ajax.BeginForm("QuickPay", "Dashboard",
new { },
new AjaxOptions() {
HttpMethod = "Post",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "quickpay-wrapper",
OnSuccess = "updatePaymentHistory",
LoadingElementId = "loading-pane"
}, new { }))
{ %>
<div class="horizontalline"><%= Html.Spacer() %></div>
<% ViewContext.FormContext.ValidationSummaryId = "valSumContainer"; %>
<p>
<%: Html.LabelFor(x => x.PaymentMethods)%>
<% if (Model.HasOnePaymentMethod) { %>
<%: Html.DisplayFor(x => x.SelectedPaymentMethodName) %>
<%: Html.HiddenFor(x => x.SelectedPaymentMethodId) %>
<% } else { %>
<%: Html.DropDownListFor(x => x.SelectedPaymentMethodId, Model.PaymentMethodsSelectList, "Select a Payment Method", new { })%>
<%: Html.HiddenFor(x => x.SelectedPaymentMethodName)%>
<script type="text/javascript">
$(function () {
$("#PaymentMethods").change(function () {
$("#SelectedPaymentMethodId").val($(this).val());
$("#SelectedPaymentMethodName").val($('option:selected', this).text());
});
});
</script>
<% } %>
<%: Html.Spacer(12, 1) %><%: Ajax.ActionLink("New Payment Method", "QuickPayNewMethod",
new AjaxOptions() { InsertionMode = InsertionMode.Replace,
UpdateTargetId = "quickpay-wrapper",
OnSuccess = "newPaymentSetup",
LoadingElementId = "loading-pane"
})%>
<%: Html.ValidationMessageFor(x => x.SelectedPaymentMethodId)%>
</p>
<p>
<%: Html.LabelFor(x => x.Amount)%>
<%: Html.TextBoxFor(x => x.Amount, new { disabled = Model.UseInvoicing ? "disabled" : String.Empty,
title = Model.UseInvoicing ? "the total payment amount of all selected invoices" : String.Empty,
@class = "small" })%>
<%: Html.ValidationMessageFor(x => x.Amount)%>
</p>
<p>
<%: Html.LabelFor(x => x.PayDate)%>
<%: Html.TextBox("PayDate", Model.PayDate.ToShortDateString(), new { @class = "medium" })%>
<%: Html.ValidationMessageFor(x => x.PayDate)%>
</p>
<script type="text/javascript">
$(function () {
quickPaySetup();
});
</script>
<div class="horizontalline"><%= Html.Spacer() %></div>
<%= FTNI.Controls.Submit("Submit Payment") %>
<%: Html.AntiForgeryToken() %>
<%: Html.ValidationMessage("Payment-Result")%>
<% } %>现在我的新支付方法面板
<script type="text/javascript">
$(function () {
newPaymentSetup();
});
</script>
<h4>New Payment Method</h4>
<% if(Model.HasPaymentMethods) { %>
<span style="float:right;">
<%: Ajax.ActionLink("Cancel", "QuickPay",
new AjaxOptions() {
HttpMethod = "Get",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "quickpay-wrapper",
OnSuccess = "quickPaySetup",
LoadingElementId = "loading-pane"
})%>
</span>
<% } %>
<div>Enter the information below to create a new payment method.</div><br />
<%= Html.ClientValidationSummary(new { id = "valSumContainer" })%>
<% Html.EnableClientValidation(); %>
<div id="new-payment-method-tabs">
<ul>
<li><a href="#new-credit-card">Credit Card</a></li>
<li><a href="#new-ach">E-Check</a></li>
</ul>
<div id="new-credit-card">
<% Html.RenderPartial("NewCreditCard", Model.CreditCardModel); %>
</div>
<div id="new-ach">
<% Html.RenderPartial("NewACH", Model.ACHModel); %>
</div>
</div>每个表单的开头都是这样的
<% using (Ajax.BeginForm("AddCreditCard", "Dashboard",
new { },
new AjaxOptions() {
HttpMethod = "Post",
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "quickpay-wrapper",
OnSuccess = "newPaymentSetup",
LoadingElementId = "loading-pane"
}, new { id="new-credit-card-form" })) { %>
<% ViewContext.FormContext.ValidationSummaryId = "valSumContainer"; %>初始负荷工作。任何ajax替换都会导致表单上下文丢失,而不管我做什么都不会重新初始化。表单回发,验证发生在服务器端。所有无效字段都会被更改(添加了css错误类),但摘要中只显示了最后一个错误。
发布于 2010-11-24 14:26:05
最后,我重新工作了我的解决方案,这样我就不再通过回调将表单写入页面。虽然这不是我想要的方法,但它确实奏效了。我选择使用jquery来显示数据,而不是更改屏幕上某个区域的内容。
理想情况下,我不必将所有表单呈现到页面上,并且可以根据需要调用它们,但似乎jquery客户端验证不会连接,除非该表单在页面加载时出现。我不确定表单元素是否需要在表单加载时出现,但这可能是我必须处理的一个限制。
另一个解决方法是将它们全部呈现到页面上,并通过jquery显示/隐藏每个表单。这与使用modals没有太大不同,但至少验证是有效的。我仍然希望看到这样一种解决方案:使用验证摘要的表单和通过数据注释进行客户端jquery验证的表单可以通过回调写入页面,并且仍然可以连接并正确工作。
https://stackoverflow.com/questions/4219463
复制相似问题