如何 post 每个子模型单独考虑验证?
How to post each submodel alone with validation into consideration?
我有一个与包含多个视图模型的 ViewModel 绑定的视图。
现在,父视图包含视图(由@html.partial 呈现),每个视图都与其相应的视图模型绑定,并具有自己的表单操作。
我的问题:
我可以正确查看数据,但我不能单独提交每个子视图,那么post每个子模型如何单独提交?
此外,当出现模型状态错误时,我如何才能引用正确的子视图?
如有任何想法,我们将不胜感激。
额外信息:
代码示例显示了我所做的事情:
视图模型:
public class ViewModelParent
{
public ViewModelChild1 ViewModelC1 {get; set;}
public ViewModelChild2 ViewModelC2 {get; set;}
public ViewModelChild3 ViewModelC3 {get; set;}
}
控制器:
public ActionResult GetParent()
{
return view(new ViewModelParent());
}
观看次数:
GetParent.cshtml
(包含每个子模型的视图)。
@model Models.ViewModelParent
@Html.Partial("~/Views/Children/GetC1.cshtml", Model.ViewModelC1)
@Html.Partial("~/Views/Children/GetC2.cshtml", Model.ViewModelC2)
@Html.Partial("~/Views/Children/GetC3.cshtml", Model.ViewModelC3)
儿童观看次数:
GetC1.cshtml
@model ViewModelChild1
<form action="@Url.Action("GetC1", "Child"" method="POST" class="smart-form" id="frm_child1">
@Html.AntiForgeryToken()
@Html.ValidationSummary()
@* controls here*@
</form>
其他子视图也是如此 GetC2.cshtml
& GetC3.cshtml
我过去做过类似的事情。
我建议将此作为一种可能的方法(假设您想坚持使用整页回发而不是走 ajax 路线)。
使用现有的父视图模型class(带有子模型)
public class ViewModelParent
{
public ViewModelChild1 ViewModelC1 {get; set;}
public ViewModelChild2 ViewModelC2 {get; set;}
public ViewModelChild3 ViewModelC3 {get; set;}
}
让分部视图各自使用父模型
@model Models.ViewModelParent
@Html.Partial("~/Views/Children/GetC1.cshtml", Model)
@Html.Partial("~/Views/Children/GetC2.cshtml", Model)
@Html.Partial("~/Views/Children/GetC3.cshtml", Model)
每个子视图都有父模型,但只包含该视图的子模型的表单元素。如果你想在每个局部视图中都有一个验证摘要,你必须有点创意 - 我稍后会解释......
例如:GetC1.cshtml
@model ViewModelParent
@using(Html.BeginForm("GetParent", "ParentControllerName", null, FormMethod.Post, new {@class="smart-form" id="frm_child1"}))
{
@Html.AntiForgeryToken()
@Html.ValidationSummaryForGroup(ViewBag.ChildType, "Child1") @* I'll explain this later *@
@* controls here - eg... *@
@Html.TextBoxFor(m => m.ViewModelChild1.Property1)
}
如果表单有效(或者 return 如果无效),那么您的控制器可以简单地分出子方法
例如:
public class ParentControllerNameController : Controller
{
public ActionResult GetParent()
{
return View(new ViewModelParent());
}
[HttpPost]
public ActionResult GetParent(ViewModelParent model)
{
if (ModelState.IsValid)
{
if (model.ViewModelC1 != null)
{
return GetC1(model.ViewModelC1);
}
else if (model.ViewModelC2 != null)
{
return GetC2(model.ViewModelC2)
}
else if (model.ViewModelC3 != null)
{
return GetC3(model.ViewModelC3)
}
} else {
// invalid!
if (model.ViewModelC1 != null)
{
ViewBag.ChildType = "Child1";
}
else if (model.ViewModelC2 != null)
{
ViewBag.ChildType = "Child2";
}
else if (model.ViewModelC3 != null)
{
ViewBag.ChildType = "Child3";
}
// needed to prevent null reference errors
if (model.ViewModelC1 == null) model.ViewModelC1 = new ViewModelChild1();
if (model.ViewModelC2 == null) model.ViewModelC2 = new ViewModelChild2();
if (model.ViewModelC3 == null) model.ViewModelC3 = new ViewModelChild3();
}
return View(model);
}
}
以上 else-if 语句将起作用,因为每个子视图仅包含该子模型的属性 - 因此其他子视图模型为空。
请注意,我在上面创建了一个新的 Html 帮助程序扩展,它包装了验证摘要,因此您可以显示特定于子模型的错误。一个简单的 display/not 显示是不够的,否则会丢失客户端验证错误。
当然,只有在每个局部视图中都有验证摘要时才需要这样做。如果只有一个验证摘要,那么您可以坚持使用简单的 @Html.ValidationSummary()
namespace System.Web.Mvc.Html
{
public static class ValidationSummaryForGroupExtensions
{
public static MvcHtmlString ValidationSummaryForGroup(this HtmlHelper html, string testValue, string expectedValue)
{
return ValidationSummaryForGroup(html, testValue, expectedValue, false);
}
/// <summary>
/// Displays a validation summary which shows serverside errors only if the specified testvalue and value are equal. Client side validation will work as normal.
/// <para>The purpose of this is to allow multiple valiation summaries (for multiple forms) on a single page.</para>
/// </summary>
/// <param name="testValue">Value to test (could be a value in viewbag)</param>
/// <param name="expectedValue">Value to expect if the server side errors are to be displayed.</param>
/// <returns></returns>
public static MvcHtmlString ValidationSummaryForGroup(this HtmlHelper html, string testValue, string expectedValue, bool excludePropertyErrors)
{
if (testValue != null && testValue.ToLower() == expectedValue.ToLower())
return html.ValidationSummary(excludePropertyErrors);
return new MvcHtmlString("<div class=\"validation-summary-valid\" data-valmsg-summary=\"true\"><ul><li style=\"display:none\"></li></ul></div>");
}
}
}
当然,您可以使用 ajax 进行部分回发 - 在这种情况下,子视图可以直接用于子模型,并且每个子视图直接回发到控制器中的相关方法。
这个很简单,在controller的post方法的handler中,调用view model中属性名称后的参数名称
所以在你的视图模型中你有:
public class ViewModelParent
{
public ViewModelChild1 viewModelC1 {get; set;}
public ViewModelChild2 viewModelC2 {get; set;}
public ViewModelChild3 viewModelC3 {get; set;}
}
在控制器的 post 处理程序中,您将需要类似以下内容:
<HttpPost()>
Function GetC1(viewModelC1 As ViewModelChild1 ) As ActionResult
在 html 中,所有属性的名称都将类似于 'viewModelC1.nameofsomething',这有助于模型绑定器映射属性。以上是VB.net不过你应该明白了。
希望对您有所帮助
安迪
我有一个与包含多个视图模型的 ViewModel 绑定的视图。
现在,父视图包含视图(由@html.partial 呈现),每个视图都与其相应的视图模型绑定,并具有自己的表单操作。
我的问题:
我可以正确查看数据,但我不能单独提交每个子视图,那么post每个子模型如何单独提交?
此外,当出现模型状态错误时,我如何才能引用正确的子视图?
如有任何想法,我们将不胜感激。
额外信息:
代码示例显示了我所做的事情:
视图模型:
public class ViewModelParent
{
public ViewModelChild1 ViewModelC1 {get; set;}
public ViewModelChild2 ViewModelC2 {get; set;}
public ViewModelChild3 ViewModelC3 {get; set;}
}
控制器:
public ActionResult GetParent()
{
return view(new ViewModelParent());
}
观看次数:
GetParent.cshtml
(包含每个子模型的视图)。
@model Models.ViewModelParent
@Html.Partial("~/Views/Children/GetC1.cshtml", Model.ViewModelC1)
@Html.Partial("~/Views/Children/GetC2.cshtml", Model.ViewModelC2)
@Html.Partial("~/Views/Children/GetC3.cshtml", Model.ViewModelC3)
儿童观看次数:
GetC1.cshtml
@model ViewModelChild1
<form action="@Url.Action("GetC1", "Child"" method="POST" class="smart-form" id="frm_child1">
@Html.AntiForgeryToken()
@Html.ValidationSummary()
@* controls here*@
</form>
其他子视图也是如此 GetC2.cshtml
& GetC3.cshtml
我过去做过类似的事情。 我建议将此作为一种可能的方法(假设您想坚持使用整页回发而不是走 ajax 路线)。
使用现有的父视图模型class(带有子模型)
public class ViewModelParent
{
public ViewModelChild1 ViewModelC1 {get; set;}
public ViewModelChild2 ViewModelC2 {get; set;}
public ViewModelChild3 ViewModelC3 {get; set;}
}
让分部视图各自使用父模型
@model Models.ViewModelParent
@Html.Partial("~/Views/Children/GetC1.cshtml", Model)
@Html.Partial("~/Views/Children/GetC2.cshtml", Model)
@Html.Partial("~/Views/Children/GetC3.cshtml", Model)
每个子视图都有父模型,但只包含该视图的子模型的表单元素。如果你想在每个局部视图中都有一个验证摘要,你必须有点创意 - 我稍后会解释......
例如:GetC1.cshtml
@model ViewModelParent
@using(Html.BeginForm("GetParent", "ParentControllerName", null, FormMethod.Post, new {@class="smart-form" id="frm_child1"}))
{
@Html.AntiForgeryToken()
@Html.ValidationSummaryForGroup(ViewBag.ChildType, "Child1") @* I'll explain this later *@
@* controls here - eg... *@
@Html.TextBoxFor(m => m.ViewModelChild1.Property1)
}
如果表单有效(或者 return 如果无效),那么您的控制器可以简单地分出子方法
例如:
public class ParentControllerNameController : Controller
{
public ActionResult GetParent()
{
return View(new ViewModelParent());
}
[HttpPost]
public ActionResult GetParent(ViewModelParent model)
{
if (ModelState.IsValid)
{
if (model.ViewModelC1 != null)
{
return GetC1(model.ViewModelC1);
}
else if (model.ViewModelC2 != null)
{
return GetC2(model.ViewModelC2)
}
else if (model.ViewModelC3 != null)
{
return GetC3(model.ViewModelC3)
}
} else {
// invalid!
if (model.ViewModelC1 != null)
{
ViewBag.ChildType = "Child1";
}
else if (model.ViewModelC2 != null)
{
ViewBag.ChildType = "Child2";
}
else if (model.ViewModelC3 != null)
{
ViewBag.ChildType = "Child3";
}
// needed to prevent null reference errors
if (model.ViewModelC1 == null) model.ViewModelC1 = new ViewModelChild1();
if (model.ViewModelC2 == null) model.ViewModelC2 = new ViewModelChild2();
if (model.ViewModelC3 == null) model.ViewModelC3 = new ViewModelChild3();
}
return View(model);
}
}
以上 else-if 语句将起作用,因为每个子视图仅包含该子模型的属性 - 因此其他子视图模型为空。
请注意,我在上面创建了一个新的 Html 帮助程序扩展,它包装了验证摘要,因此您可以显示特定于子模型的错误。一个简单的 display/not 显示是不够的,否则会丢失客户端验证错误。
当然,只有在每个局部视图中都有验证摘要时才需要这样做。如果只有一个验证摘要,那么您可以坚持使用简单的 @Html.ValidationSummary()
namespace System.Web.Mvc.Html
{
public static class ValidationSummaryForGroupExtensions
{
public static MvcHtmlString ValidationSummaryForGroup(this HtmlHelper html, string testValue, string expectedValue)
{
return ValidationSummaryForGroup(html, testValue, expectedValue, false);
}
/// <summary>
/// Displays a validation summary which shows serverside errors only if the specified testvalue and value are equal. Client side validation will work as normal.
/// <para>The purpose of this is to allow multiple valiation summaries (for multiple forms) on a single page.</para>
/// </summary>
/// <param name="testValue">Value to test (could be a value in viewbag)</param>
/// <param name="expectedValue">Value to expect if the server side errors are to be displayed.</param>
/// <returns></returns>
public static MvcHtmlString ValidationSummaryForGroup(this HtmlHelper html, string testValue, string expectedValue, bool excludePropertyErrors)
{
if (testValue != null && testValue.ToLower() == expectedValue.ToLower())
return html.ValidationSummary(excludePropertyErrors);
return new MvcHtmlString("<div class=\"validation-summary-valid\" data-valmsg-summary=\"true\"><ul><li style=\"display:none\"></li></ul></div>");
}
}
}
当然,您可以使用 ajax 进行部分回发 - 在这种情况下,子视图可以直接用于子模型,并且每个子视图直接回发到控制器中的相关方法。
这个很简单,在controller的post方法的handler中,调用view model中属性名称后的参数名称
所以在你的视图模型中你有:
public class ViewModelParent
{
public ViewModelChild1 viewModelC1 {get; set;}
public ViewModelChild2 viewModelC2 {get; set;}
public ViewModelChild3 viewModelC3 {get; set;}
}
在控制器的 post 处理程序中,您将需要类似以下内容:
<HttpPost()>
Function GetC1(viewModelC1 As ViewModelChild1 ) As ActionResult
在 html 中,所有属性的名称都将类似于 'viewModelC1.nameofsomething',这有助于模型绑定器映射属性。以上是VB.net不过你应该明白了。
希望对您有所帮助 安迪