我正在进行Ajax调用并向MVC2应用程序内的表单添加内容。 我需要通过验证我的新内容来更新客户端验证元数据。
<script type="text/javascript">
//<![CDATA[
if (!window.mvcClientValidationMetadata) { window.mvcClientValidationMetadata = []; }
window.mvcClientValidationMetadata.push({"Fields":[{"
...
</script>
有没有办法为局部视图生成此元数据?
提前致谢。
答案 0 :(得分:6)
我正在将这个头撞在墙上几天,并且要沿着删除表格标签的路线走下去,但是如果你仍然感兴趣,那就让它以一种稍微不那么神奇的方式工作。我的方案类似,因为我有一个表单,其中包含最初要验证的元素集合,但用户可以通过ajax动态添加新行。
我会把它分解,所以希望看到发生的事情会更容易。查看MVC源代码,表单和验证大致如下:
Html.BeginForm()输出开始表单标签然后创建并返回一个新的MvcForm实例,除了使表单的范围更容易为您管理外,它不会向外做很多事情。 但它会创建一个新的FormContext并将其存储在ViewContext.FormContext中。正是这个FormContext跟踪客户端验证。
Html.BeginForm()做的最后一件事是使用form标签的id设置新FormContext的FormId属性。这是必需的,因此客户端脚本可以匹配表单和验证规则。
Html.EndForm()处理MvcForm。此Dispose方法输出表单结束标记,然后调用ViewContext.OutputClientValidation(),它可用于输出javascript。最后,它删除当前的FormContext并将其设置回父FormContext,如果没有,则返回null。
因此,为了不输出表单标记,我们需要从MvcForm构造函数/析构函数中获取一些FormContext管理。
因此,在我的部分视图中,我执行了以下操作:
在顶部,我检查ViewContext.FormContext是否有值。如果是这样,我们处于初始负载,所以不需要乱七八糟。如果没有,它是一个ajax调用,所以我启用客户端验证,直接创建一个新的MvcForm(不是与BeginForm) - 这会导致创建一个FormContext - 并将FormContext.FormId设置为相同作为我的父页面
在视图的最后,我检查是否有表单实例,如果有,请调用ViewContext.OutputClientValidation()并将ViewContext.FormContext重置为null。我没有Dispose()MvcForm,因为它会输出结束标记而MvcForm不包含一次性对象。
视图的骨架如下:
<%
MvcForm dummyForm = null;
if (this.ViewContext.FormContext == null)
{
Html.EnableClientValidation();
dummyForm = new MvcForm(this.ViewContext);
this.ViewContext.FormContext.FormId = "mainform";
}
%>
// standard partial view markup goes here
<%
if (dummyForm != null)
{
this.ViewContext.OutputClientValidation();
this.ViewContext.FormContext = null;
}
%>
你可以很容易地把它包装成扩展方法
菲尔
答案 1 :(得分:2)
最后让它发挥作用。
答案很简单:不要与MicrosoftMvcValidation.js共度时光。它是使用脚本#生成的,这使得难以扩展。
切换到 xVal 和 jQuery验证。 它不需要表单来生成客户端验证元数据。 另外,为了加载AJAX请求的验证,您只需在获得新的Html后调用以下内容:
lForm.find("#placeholder").empty();
lForm.valid();
lForm.find("#placeholder").html(responseHtml);
就是这样。首先删除旧内容。比重新运行验证以摆脱可能过时的验证错误。比添加新内容。像cham一样工作。
此外,jQuery Validation可以非常轻松地启用或禁用某个字段的验证(条件验证)。
答案 2 :(得分:1)
我有同样的问题并使用Future文件解决,在MicrosoftMvcJQueryValidation.js中我改变了文件和文件,这个:
$(document).ready(function () {
var allFormOptions = window.mvcClientValidationMetadata;
if (allFormOptions) {
while (allFormOptions.length > 0) {
var thisFormOptions = allFormOptions.pop();
__MVC_EnableClientValidation(thisFormOptions);
}
}
});
for:
function chargeValidation() {
var allFormOptions = window.mvcClientValidationMetadata;
if (allFormOptions) {
while (allFormOptions.length > 0) {
var thisFormOptions = allFormOptions.pop();
__MVC_EnableClientValidation(thisFormOptions);
}
}
}
并且在使用我调用'chargeValidation()'后关闭表单的内容中,这解决了我使用包含表单验证的$ .get(action)的问题。
我希望能帮到你!
答案 3 :(得分:0)
由于我使用的是Facebox,我将其添加到了facebox代码中,但是您可以将其添加到任何需要的地方,或者在回调中,如果你的模态或任何你加载的内容都有afterLoaded事件。
我将它们包装在try / catch中,以防我使用没有验证内容的facebox。
只需在加载内容后运行这两行:
try {
Sys.Application.remove_load(arguments.callee);
Sys.Mvc.FormContext._Application_Load();
} catch (err) {/* MVC Clientside framework is likely not loaded*/ }
答案 4 :(得分:0)
我取得了一些进展,但我并不高兴。
问题#1:除非您的部分中有Html.BeginForm(),否则不会生成客户端验证元数据。在我的情况下,这是假的,因为我不更新整个表单,我更新它的部分。
问题#1的解决方案:在局部视图中添加表单,让MVC生成客户端验证MetaData并使用操作过滤器删除表单标记。我们称之为 Hack#1 。
public class RemoveFormFilterAttribute : ActionFilterAttribute
{
private static readonly MethodInfo SwitchWriterMethod = typeof(HttpResponse).GetMethod("SwitchWriter", BindingFlags.Instance | BindingFlags.NonPublic);
private TextWriter _OriginalWriter;
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
_OriginalWriter = (TextWriter)SwitchWriterMethod.Invoke(HttpContext.Current.Response, new object[] {new HtmlTextWriter(new StringWriter())});
}
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
if (_OriginalWriter != null)
{
HtmlTextWriter lTextWriter =(HtmlTextWriter) SwitchWriterMethod.Invoke(HttpContext.Current.Response, new object[] {_OriginalWriter});
string lOriginalHTML = lTextWriter.InnerWriter.ToString();
string lNewHTML = RemoveFormTags(lOriginalHTML);
filterContext.HttpContext.Response.Write(lNewHTML);
}
}
问题#2:当我拥有新内容的元数据时,页面的初始客户端验证元数据已经消失。
问题#2的解决方案:存储初始元数据(硬拷贝)并使用新的fieds更新它,而不是调用您提到的方法让MVC知道新的东西到达。我们称之为 Hack#2。
<script type="text/javascript">
var pageMvcClientValidationMetadata;
$(document).ready(function() {
$("input[name='PaymentTypeName']").change(PaymentTypeChanged);
//create a back-up of the ValidationMetadata
pageMvcClientValidationMetadata = JSON.parse(JSON.stringify(window.mvcClientValidationMetadata));
});
function PaymentTypeChanged() {
var selectedPaymentType = $("input[name='PaymentTypeName']:checked").val();
$.ajax(
{
url: 'PersonalData/GetPaymentTypeHtml?&paymentType=' + selectedPaymentType,
type: "GET",
cache: false,
success: GetPaymentTypeHtml_Success
});
}
function GetPaymentTypeHtml_Success(result) {
$('#divPaymentTypeDetails').html(result);
UpdateValidationMetaData();
}
function UpdateValidationMetaData() {
//update the ValidationMetadata
for (i = 0; i < window.mvcClientValidationMetadata[0].Fields.length; i++) {
pageMvcClientValidationMetadata[0].Fields.push(window.mvcClientValidationMetadata[0].Fields[i]);
}
//restore the ValidationMetadata
window.mvcClientValidationMetadata = JSON.parse(JSON.stringify(pageMvcClientValidationMetadata));
//Notify the Validation Framework that new Metadata exists
Sys.Application.remove_load(arguments.callee);
Sys.Mvc.FormContext._Application_Load();
}
现在。任何改进都将受到赞赏。
Hack#1:如何在没有实际表单的情况下生成客户端验证元数据?
HAck#2:我如何附加页面验证元数据?