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

时间:2019-04-22 14:44:03

标签: asp.net-core model-view-controller c#-4.0 asp.net-core-mvc partial-views

我无法将使用局部视图动态创建的子复杂对象集合绑定到视图模型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调用此操作方法以添加动态联系人详细信息元素,并将部分视图返回为html,并且效果很好。

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

可使用以下方法将初始联系人详细信息添加到主视图,请按照此链接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);
}

1 个答案:

答案 0 :(得分:1)

为了进行绑定,输入名称要遵循一个特定的约定,该约定映射到您要绑定的对象。尽管您的问题尚不清楚,但我最好的猜测是您正在尝试最终绑定到EmployeeViewModel的实例,这意味着您的联系信息输入将需要使用以下名称:EmployeeContact[0].Telephone,但是当您将ContactDetailViewModel的实例作为部分视图的“模型”传递时,名称将仅为Telephone,更糟糕的是,这些相同的名称将一遍又一遍地重复,即的每个联系人信息集您创建的字段都将有一个仅名为Telephone的输入。

总之,您需要整个模型的上下文来生成正确的输入名称。您有两种选择。

由于您是通过AJAX请求检索字段集的,因此可以将“前缀”与该请求一起使用。换句话说,您可以跟踪索引值,计算已添加的节数,然后与对新节的请求一起发送

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等库,您可以设置绑定到特定JavaScript数组的“ foreach”构造,该JavaScript数组使用此模板来呈现该数组中的项目。然后,添加一组新的输入就像将新项添加到数组一样简单。您将需要做一些工作来基于数组中项目的索引来自定义输入名称,但是所有这些客户端框架都有这样做的方法。这样做还有一个好处,就是每次您要添加新部分时都不必发出AJAX请求。