【问题标题】:MVC3 Unobtrusive Validation Not Working after Ajax CallAjax 调用后 MVC3 不显眼的验证不起作用
【发布时间】:2011-08-13 05:15:02
【问题描述】:

好的,这就是交易,我已经看到一些关于 SO 与此问题相关的帖子,但没有什么对我有用。

基本上,我选择了从部分视图加载的下拉菜单,我正在尝试根据之前选择的下拉菜单过滤每个后续下拉菜单的内容。

如果我只是在 div 容器中调用部分视图并加载页面,则数据注释的验证工作正常,主要是必需属性

但是,如果我尝试通过 AJAX 加载与此处设置相同的部分,则必需的验证不起作用,任何人都可以在此之后发布表单和 KABOOM。

我发现有人说,在 Success 回调中,您需要让客户端验证器重新解析表单,我正在尝试,但它似乎不起作用。

我有一个看起来像这样的视图...

  @model Area51.Models.Workflow.AddReportableItemToBatchActionModel
@{
    ViewBag.Title = "Add Reportable Item to Batch";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<script type="text/javascript">

    $(function () {
        var fadeDelay = 150;

        $(".jqDatePicker").datepicker({
            dateFormat: 'm/d/yy',
            onSelect: function (date) {
                $("#categoryContainer").show(fadeDelay);
            }
        });

        $('#Category').change(function () {
            RetrieveItemsForCategory();
            $("#itemContainer").show(100);
        });

        $('#Item').live('change', function () {
            RenderPartialForUOMByItem();           
        });



        function RetrieveItemsForCategory() {

            var category = $("#Category :selected").val();

            $.ajax({
                type: "POST",

                url: '@Url.Action("RenderPartialForLocationItemsByCategory","BatchWorkflow")',

                data: 'category=' + category,

                success: function (result) {
                    $("#itemContainer").html(result.toString());
                    $("#itemContainer").show(100);
                    RebindValidation();
                },

                error: function (req, status, error) {
                    alert("Sorry! Could not request items for your selection at this time.");
                }

            });


        }


        function RenderPartialForUOMByItem() {

            var item = $("#Item :selected").val();

            $.ajax({
                type: "POST",

                url: '@Url.Action("RenderPartialForUOMByItem","BatchWorkflow")',

                data: "item=" + item,

                success: function (result) {
                    $("#quantityContainer").html(result.toString());
                    $("#quantityContainer").show(100);
                    RebindValidation();
                },

                error: function (req, status, error) {
                    alert("Sorry! Could not request items for your selection at this time.");
                }

            });
        }

        function RebindValidation() {
            alert("Rebinding Validation");
            $.validator.unobtrusive.parse("#frmAddItem");
        }

    });      // End OnLoad Event
</script>

<h3 class="pageHeader">Batch : @Model.BatchName</h3>

<div align="center">

@{Html.BeginForm("AddItemToBatch", "BatchWorkflow", null, FormMethod.Post, new { id = "frmAddItem" });}

    @Html.ValidationSummary(true)

    <fieldset style="width:60%">
        <legend>Add an Item to the Batch</legend>     

     <div>       
          <h3>Select Date Item was Added</h3>
          @Html.EditorFor(x => x.EventDate,null)
          <br />
      </div>

      <div id="categoryContainer" style="display:none"> 
        <hr />
          <h3>Select an Inventory Category</h3>
          @Html.EditorFor(x => x.Category,null)
          <br />
      </div>

      <div id="itemContainer" style="display:none"> 
        @*   @{Html.RenderAction("RenderPartialForLocationItemsByCategory", "BatchWorkflow", new { category = Model.Category });}*@
      </div>


      <div id="quantityContainer" style="display:none"> 
        @*  @{Html.RenderAction("RenderPartialForUOMByItem", "BatchWorkflow", new { item = Model.Item });}*@
      </div>

      <div id="reportingDataContainer" style="display:none"> 
        <hr />
          <h3>What quantity of the batch was affected by this addition?</h3>
          @Html.EditorFor(x => x.ConsumedWineQuantity) (Gallons)
        <br />
        <hr />
          <h3>What was the increase in Batch Volume as a result of this addition?</h3>
          @Html.EditorFor(x => x.ProducedWineQuantity) (Gallons)
      </div>

        <div style="display:block">
        <div></div>        
            <span><button type="button" id="btnCancel" class="linkButton" value="Cancel" onclick="location.href='@Url.Action("Home","Home",null)';">Cancel</button></span>  
            <span><button type="submit" id="btnSubmit" class="linkButton" value="Add">Add Item</button></span>
        </div>


    </fieldset>
        @{ Html.EndForm(); }
</div>

Partial Views 很简单,基本上是这样的……

@model Area51.Models.Workflow.AddReportableItemToBatchActionModel

      <hr />
          <h3>Select the Item to Add</h3>
          @Html.EditorFor(x => x.Item)
          <br />

同样,如果我只是 RenderPartial,验证工作正常,但是当我尝试通过 ajax 进行验证时,验证就会消失。 “重新绑定验证”警报触发,但 $.validator.unobtrusive.parse("#frmAddItem");好像什么都没做。

任何人都可以帮助我解决我的遗漏吗?将不胜感激。

好的,我尝试添加 $.validator.unobtrusive.parse("#frmAddItem");在文档就绪事件中的部分视图的底部,它似乎也不起作用,基本上没有任何改变,我仍然可以提交表单。

我确实在这里找到了一个帖子:http://xhalent.wordpress.com/2011/01/24/applying-unobtrusive-validation-to-dynamic-content/,其中提到当 jqvalidation 的 MVC 版本看到一个表单已经绑定了验证规则时,它会忽略 .validator 调用。我实现了这位先生使用的脚本扩展,现在验证正在使用新扩展重新绑定到表单。我可以通过将 html 附加到表单并调用新的扩展来测试它,它重新绑定到新的文本框。

但是,这仍然没有完全解决问题。我使用 Firebug 检查了从 ajax 调用返回的字段的实际内容,并注意到一些非常奇怪的事情。

当我使用 RenderPartial 调用操作时,它会写出以下选择:

<select id="Item" name="Item" data-val-required="The Item field is required." data-val-number="The field Item must be a number." data-val="true">

但是,当我对相同的控制器操作进行 ajax 调用时,它会返回:

<select id="Item" name="Item">

我也尝试将脚本标签添加到局部视图中,但并没有解决问题。 ajax 调用会剥离不显眼的验证标签是否有某些原因?

好的,那么发生了什么,我有一个用于下拉列表的编辑器模板,该模板采用选择列表并将其转换为 html 选择。我发现一篇文章提到,为了在编辑器模板上写出数据验证属性,您必须有一个表单上下文。由于 Html.RenderPartial 是在表单中完成的,因此编辑器模板具有可以使用的表单上下文。当我只是试图通过 ajax 调用部分时,没有可以使用的表单上下文,而不是抱怨它只是没有写出数据验证属性。在 SelectListDropDown 的编辑器模板中添加新的表单上下文解决了这个问题。

@{ // fix to stop stupid crappy brad wilson mvc3 code from stripping the jq data valdiation attributes
    if (ViewContext.FormContext == null)
    {
        ViewContext.FormContext = new FormContext();
    }
}

【问题讨论】:

标签: c# ajax asp.net-mvc-3 unobtrusive-validation asp.net-mvc


【解决方案1】:

$.validator.unobtrusive.parse("#frmAddItem"); 可以工作。请注意,它必须在您通过 ajax 加载的部分中(在部分中的表单下方)

<form id="frmAddItem" method="POST" action="...">
    <!-- all the items -->
</form>
<script type="text/javascript">
    $.validator.unobtrusive.parse("#frmAddItem");
</script>

【讨论】:

  • 好的,在部分末尾的表单中添加脚本后,又名: 而不是尝试文档就绪事件,它似乎按预期工作。我将此答案标记为正确,因为无法通过 ajax 进行验证的问题是一个单独的问题。非常感谢 jgauffin
  • 请注意,我采用了稍微不同的方法,并将其添加到我的ajax调用$.ajax({success:function(){$.validator.unobtrusive.parse('form');}});的成功函数中@
【解决方案2】:

我正在添加我的经验,因为上述建议对我不起作用。 此解决方案确实并且可能会帮助从搜索引擎定向到此页面的其他人:

OnSuccess="$.validator.unobtrusive.parse('YourFormName');"添加到你的AjaxOptions

使用 Ajax.ActionLink 的示例:

@Ajax.ActionLink("This is a test to get unobtrusive javascript working",
                 "Name_of_your_controller_action",
                 new AjaxOptions { HttpMethod = "POST", 
                                   InsertionMode = InsertionMode.Replace, 
                                   UpdateTargetId = "UserDiv", 
                                   OnSuccess="$.validator.unobtrusive.parse('UserDetailsForm');"  
                                 }
                )

此解决方案位于: http://blog.janjonas.net/2011-07-24/asp_net-mvc_3-ajax-form-jquery-validate-supporting-unobtrusive-client-side-validation-and-server-side-validation

【讨论】:

    【解决方案3】:

    我写了这个小sn-p,你可以把它放在你的javascript文件中,它会处理你所有的ajax加载的表单。

    //enable unobtrusive validation for ajax loaded forms
    $(document).ajaxSuccess(function (event, xhr, settings) {
        //process only if html was returned
        if ($.inArray('html', settings.dataTypes) >= 0) {
            //will parse the element with given id for unobtrusive validation
            function parseUnobtrusive(elementId) {
                if (elementId) {
                    $.validator.unobtrusive.parse('#' + elementId);
                }
            }
    
            //get the form objects that were loaded.  Search within divs
            //in case the form is the root element in the string
            var forms = $('form', '<div>' + xhr.responseText + '</div>');
    
            //process each form retrieved by the ajax call
            $(forms).each(function () {
                //get the form id and trigger the parsing.
                //timout necessary for first time form loads to settle in
                var formId = this.id;
                setTimeout(function () { parseUnobtrusive(formId); }, 100);
            });
        }
    });
    

    【讨论】:

    • setTimeout 帮助了我。我讨厌添加这样的东西 - 看起来太脆弱了。
    • 由于 setTimeout 而被否决。如此丑陋的做法。
    【解决方案4】:

    另一种选择,相当诡计,对我有用。只需在 ajax 调用返回的部分视图的开头添加以下行

    this.ViewContext.FormContext = new FormContext(); 
    

    Reference

    【讨论】:

    • 啊,所以你在部分而不是编辑器模板中新建了表单上下文。老实说,模板似乎更加模块化,因为它适用于任何视图的任何调用。您可能想要做的一件事是在创建新上下文并覆盖旧上下文之前检查上下文是否为空...
    • @DavidC 选择编辑器模板还是部分,这取决于场景。对于第一个页面加载,上下文不为空,但在所有 ajax 调用之后,上下文为空。如果上下文设置为新的,即使它不为空,真的会受到伤害吗?
    • 真的,这取决于场景和您的基础架构,有些人甚至不使用模板。但是如果你走模板路线,它会更加模块化和干燥。至于你的第二个问题,我想这将取决于表单上下文在你踩到它之前还有哪些其他验证数据。
    【解决方案5】:

    我只能让它在OnComplete而不是OnSuccess内部工作:

    这是 AJAX 代码:

    @using (Ajax.BeginForm("Index", null, 
                           new AjaxOptions { OnSuccess = "onSuccess", 
                                             OnComplete = "onComplete"}, 
                           new { id = "mainForm" }))
    

    这是我的脚本:

    function onComplete(result) {
        $.validator.unobtrusive.parse("#mainForm");
        alert("Complete");
    };
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-11-16
      • 1970-01-01
      • 2015-05-13
      • 1970-01-01
      • 2018-11-06
      • 1970-01-01
      • 2021-02-09
      • 1970-01-01
      相关资源
      最近更新 更多