2011-08-13 51 views
34

好的,这是交易,我已经看到有关此问题的SO上的一些帖子,但没有任何工作适合我。MVC3不显眼的验证无法在Ajax调用后工作

基本上,我选择了从部分视图加载的下拉列表,我试图根据之前选择的下拉列表筛选每个后续下拉列表的内容。

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

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

我发现有人说在成功回调中,你需要让客户端验证器重新解析表单,并且我正在尝试这样做,但似乎没有工作。

我有一个看起来像这样的观点...

@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> 

的部分景色都非常简单,基本上是这样的......

@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”);似乎没有做一件事情。

任何人都可以帮助我失去了什么?这将不胜感激。

< =======================更新1 ==================== =========>

好的,我试着添加$ .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调用会剥离不显眼的验证标签有什么原因吗?

< ======================= UPDATE 2 ==================== =========>

好了,发生了什么事,是我曾经对自己采取了选择列表,并将其转换为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(); 
    } 
} 
+0

可能的重复[麻烦越来越不引人注目的验证使用mvc 3在jquery ajax后](http: //stackoverflow.com/questions/7005052/trouble-getting-unobtrusive-validation-working-with-mvc-3-on-jquery-ajax-post) – jgauffin

+0

还复制的:http://stackoverflow.com/questions/6812779/MVC-3-剃刀负载局部与验证 – jgauffin

+1

添加ViewContext.FormContext东西固定我的问题。 – K0D4

回答

67

$.validator.unobtrusive.parse("#frmAddItem");将工作。请注意,必须在局部,你可以通过AJAX(在部分下面的表格)加载

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

好的,在部分,又名的端部的形式添加刚好脚本后:<脚本类型=“文本/ JavaScript的”> $ .validator.unobtrusive.parse(“#frmAddItem”); 而不是尝试文档就绪事件,它似乎按预期工作。我正确地标记了这个答案,因为在ajax上没有通过验证的问题是一个单独的问题。感谢jgauffin –

+0

+1真棒,花了我很长时间才找到这个问题的解决方案 – Liam

+9

只需要注意,我采取了一个稍微不同的方法,并将其添加到我的ajax调用成功函数'$ .ajax({success:function( ){$。validator.unobtrusive.parse('form');}});' – Liam

8

我加入我的经验,上述建议并没有为我工作。 该解决方案也并可能帮助别人是那些获得指向此页面的搜索引擎:

使用Ajax.ActionLink添加OnSuccess="$.validator.unobtrusive.parse('YourFormName');"你AjaxOptions

一个例子:

@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

4

另一种选择,而不是欺骗,这为我工作。只需添加以下行正在由AJAX调用返回的局部视图

this.ViewContext.FormContext = new FormContext(); 

Reference

+0

啊,所以你在部分而不是编辑器模板中创建了表单上下文。老实说,模板似乎更加模块化,因为它可以用于任何视图上的任何呼叫。你可能想要做的一件事是在创建一个新文件之前检查上下文是否为空,并覆盖旧的文件... –

+0

@DavidC寻找编辑器模板还是部分取决于场景。对于第一页加载,上下文不为空,但毕竟ajax调用上下文为空。如果上下文设置为新的,即使它不为空,它是否真的会受到伤害? – bjan

+0

确实取决于场景和基础设施,有些人甚至不使用模板。但是,如果你走模板路线,它更模块化和干燥。至于你的第二个问题,我想这将取决于在你踩踏它之前,表单上下文所具有的其他验证数据。 –

7

我写了这个小片段,将可以在您的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); 
     }); 
    } 
}); 
+0

setTimeout帮助我。我讨厌添加这样的东西 - 虽然看起来太脆弱了。 – Andy

+0

由于setTimeout而被降级。这样一个丑陋的方法。 –

+1

我们赞成丑陋? Upvoted因为我喜欢布丁。 – 2015-06-10 12:50:11

1

我只能得到它的验证来的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"); 
}; 
相关问题