注入Ajax内容的MVC2客户端验证

时间:2010-05-18 13:17:21

标签: ajax validation asp.net-mvc-2 client-side

我正在进行Ajax调用并向MVC2应用程序内的表单添加内容。 我需要通过验证我的新内容来更新客户端验证元数据。

 <script type="text/javascript"> 
//<![CDATA[
if (!window.mvcClientValidationMetadata) { window.mvcClientValidationMetadata = []; }
window.mvcClientValidationMetadata.push({"Fields":[{"
...
</script>

有没有办法为局部视图生成此元数据?

提前致谢。

5 个答案:

答案 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:我如何附加页面验证元数据?