如何将使用局部视图创建的动态复杂对象绑定到视图模型中的集合 属性

How to bind dynamic complex objects created using partial-view to a collection property in view-model

我无法将使用局部视图动态创建的子复杂对象集合绑定到视图模型 IEnumerable 属性.

我已经使用我在这个博客 https://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/ 上找到的技术成功地将使用局部视图动态创建的对象绑定到视图模型。我采用了相同的技术,但无法将集合绑定到视图模型中的 IEnumerable 属性。

[BindRequired]
public class EmployeeViewModel
{
   other properties....
   public IEnumerable<ContactDetailViewModel> EmployeeContact { get; set; }
}

[BindRequired]
public class ContactDetailViewModel
{
   // I use this as my indexer for dynamic elements
   public string RecordId { get; set; } = Guid.NewGuid().ToString();

   public string Telephone { get; set; }

   public string EmailAddress { get; set; }

   public string ContactDescription { get; set; }
}

我通过 ajax 调用此操作方法以添加动态联系人详细信息元素,它 returns 局部视图为 html 并且工作正常。

[Route("[action]", Name = "BlankEmployeeContactDetail"), HttpGet("AddBlankContactDetail")]
public PartialViewResult AddBlankContactDetail()
{
            return PartialView("_ContactInformation", new     ContactDetailViewModel());
}

初始联系人详细信息已添加到主视图使用以下内容,请按照此link https://1drv.ms/u/s!AkRSHVUtFlKhuHaxH96Ik4ineATE 下载主视图和局部视图cshtml 文件。还值得注意的是,当我包含此部分视图时,模型绑定对所有其他属性都失败,但当我将其注释掉时有效。我很困惑,非常感谢你能给我的任何帮助。

<section id="widget-grid" class="">
   <div class="row contactContainer">
     @{ await Html.RenderPartialAsync("_ContactInformation", new ContactDetailViewModel()); }
   </div>
</section>

这是我尝试将发布的数据绑定到的控制器操作方法:

[Route("[action]"), HttpPost, AllowAnonymous, ValidateAntiForgeryToken]
        public IActionResult Register([FromForm] EmployeeViewModel model, [FromQuery] string returnUrl = null)
{
    if (ModelState.IsValid)
    {

    }

    return View(model);
}

为了绑定,输入名称很大程度上遵循映射到您要绑定的内容的特定约定。虽然你的问题还不清楚,但我最好的猜测是你试图最终绑定到 EmployeeViewModel 的实例,这意味着你的联系信息输入需要像这样的名称:EmployeeContact[0].Telephone,但是当你将 ContactDetailViewModel 的实例作为局部视图的 "model" 传递,名称将只是 Telephone,更糟糕的是,这些相同的名称将一遍又一遍地重复,即每个联系信息您创建的一组字段都将有一个名为 Telephone.

的输入

总而言之,您需要整个模型的上下文才能生成正确的输入名称。你有几个选择。

由于您是通过 AJAX 请求检索字段集,因此可以传递 "prefix" 以与该请求一起使用。换句话说,您可以跟踪一个索引值,计算您添加了多少这些部分,然后连同对新部分的请求一起发送

prefix: 'EmployeeContact[' + (i + 1) + ']',

那么,在你的局部视图中:

@{ await Html.RenderPartialAsync("_ContactInformation", new ContactDetailViewModel(), new ViewDataDictionary { TemplateInfo = new TemplateInfo { HtmlFieldPrefix = ViewBag.Prefix } } ); }

这有点老套,但老实说可能很容易出错。更好的选择是采用完全不同的方法。与其回调获取局部视图,不如将其定义为模板一次:

<script type="text/html" id="ContactInformationTemplate">
    <!-- HTML for contact information inputs -->
</script>

然后,使用 Vue、React、Angular 等库,您可以设置一个 "foreach" 结构绑定到特定的 JavaScript 数组,该数组使用此模板来渲染该数组中的项目。然后,添加一组新的输入就像向数组中添加一个新项一样简单。您将不得不做一些工作来根据数组中项目的索引自定义输入名称,但所有这些客户端框架都有办法做到这一点。这还有一个附带好处,即不必在每次要添加新部分时都发出 AJAX 请求。