如何 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不过你应该明白了。

希望对您有所帮助 安迪