我在这里放了一个小例子来复制问题。 我有一个强类型的局部视图_Name.cshtml:
@model ValidationInPartial.ViewModels.MyViewModel
<h2>@ViewBag.Message</h2>
<fieldset>
<legend>Name</legend>
<div class="editor-label">
@Html.LabelFor(model => model.MyName)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.MyName)
@Html.ValidationMessageFor(model => model.MyName)
</div>
<a href="#" id="reload">Reload Name</a>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
<script type="text/javascript">
$(document).ready(function () {
$("#reload").click(function () {
$("#divName").load("Home/NameReload");
});
});
</script>
最初加载并显示在主Index.cshtml
中<div id="divForm">
@using (Html.BeginForm()) {
<div id="divName">
@Html.Partial("_Name")
</div>
}
</div>
字段MyName是必需的,验证是通过MyViewModel中的Required属性实现的。
namespace ValidationInPartial.ViewModels
{
public class MyViewModel
{
[Required(ErrorMessage = "Please enter a Name.")]
public string MyName { get; set; }
}
}
第一次加载页面后,如果单击“创建”按钮,该字段将清空验证消息“请输入名称”。显示在田野旁边,田地本身变成粉红色,这是预期的行为。 现在通过单击“重新加载名称”链接,进行ajax调用(jquery.load(...)),重新加载部分,这里是控制器代码:
public PartialViewResult NameReload()
{
MyViewModel myViewModel = new MyViewModel();
ViewBag.Message = "Name Reloaded";
return PartialView("_Name", myViewModel);
}
这次如果单击“创建”按钮使该字段为空,则虽然该字段变为粉红色,但该字段旁边不会显示验证消息。 事实证明,当重新加载部分时,@ Html.ValidationMessageFor不会第一次呈现验证消息。
这是我使用的jquery文件
<script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
我想知道这是Razor引擎呈现@ Html.ValidationMessageFor的方式中的错误还是jquery的问题? 知道为什么会这样吗?
我还读过某个地方,ajax调用丢失了页面的所有脚本,实际上我必须在部分内部保留任何javascript代码,以便可以再次渲染和使用它们。
与此同时,我找到了一种解决方法,即在部分中手动渲染应该由@ Html.ValidationMessageFor呈现的内容:
<span class="field-validation-valid" data-valmsg-replace="true" data-valmsg-for="MyName"></span>
然而,这种解决方法意味着如果我们在ViewModel中的Required属性中更改验证类型或仅更改验证消息,我们需要在视图中修改此硬编码的html片段。
答案 0 :(得分:18)
@NickBork在这里有一个很好的答案。关键是ASP.NET的MVC渲染引擎如果不认为有表单就不会输出验证脚本。这个例子给出了hacks它购买放入一个表单,然后选择了一个HTML的内部部分被返回,基本上抛弃了表单的外包装。
还有另一种方法,您可以获得您的观点:
ViewContext.FormContext = new FormContext();
使用此方法,实际上不会有FORM代码输出,但验证标记将在那里。
谢谢, 约翰
答案 1 :(得分:17)
除非您的字段包含在FORM中,否则不会呈现验证标记(范围标记,自定义字段属性等)。验证插件本身不适用于表单之外的元素。
当ASP.NET渲染部分视图时,控件不在表单内,因此不会渲染元素。
当您加载部分内容时,您需要使用jQuery选择器解析HTML。
在下面的示例中,我在包含行的父视图页面上有一个TBODY。当我需要添加其他行时,我会调用一个包含表单,表格,行和行集合的视图。
$.ajax({
type: "POST",
url: "/controller/action",
data: ({Your: 'dataHere'}),
dataType: "html",
success:
function(response){
$('tbody').append($('tbody',$(response)).html());
//The validation plugin can't bind to the same form twice.
//We need to remove existing validators
$('form').removeData("validator");
//Refresh the validators
$.validator.unobtrusive.parse(document);
},
error:
function(){
alert('An error occured while attempting to add the new content');
}
});
请注意,我正在使用jQuery选择器来选择使用AJAX加载的View / PartialView内部的行:
$('tbody',$(response)).html()
包装器的其余部分只是将AJAX View / PartialView中的行附加到调用父项tbody
:
$('tbody').append($('tbody',$(response)).html());
其他一些注释,在表单上运行验证程序插件后,如果不重新添加它就无法再次调用它(请参阅jquery.validate.unobtrusive not working with dynamic injected elements)
要解决此问题,我首先调用以下方法删除所有验证器:
$('form').removeData("validator");
$("form").removeData("unobtrusiveValidation");
然后我使用以下内容刷新验证器:
$.validator.unobtrusive.parse(document);
答案 2 :(得分:1)
我不记得我在哪里找到了解决方案。原因是您正在将一个PartialView加载到已由jquery.validator.unobtrusive库解析的View中。您需要重新解析不显眼的库
function ReparseValidation(){
jQuery.validator.unobtrusive.parse("#yourcontainer");
}