【问题标题】:How to bind dynamic complex objects created using partial-view to a collection property in view-model如何将使用局部视图创建的动态复杂对象绑定到视图模型中的集合属性
【发布时间】:2019-04-22 14:44:02
【问题描述】:

我无法将使用局部视图动态创建的子复杂对象集合绑定到视图模型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);
}

【问题讨论】:

  • 我不明白你在哪里绑定模型。你的动作没有参数,你直接实例化你的视图模型。
  • 您好,感谢您的评论,我在上面的链接中附加了控制器,但我将编辑以包含接收发布数据的操作方法。

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


【解决方案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”构造,该数组使用此模板呈现该数组中的项目。然后,添加一组新的输入就像在数组中添加一个新项一样简单。您必须做一些工作来根据数组中项目的索引自定义输入名称,但所有这些客户端框架都有办法做到这一点。这样做还有一个附带好处,就是您不必每次想要添加新部分时都发出 AJAX 请求。

【讨论】:

  • 美好的一天,感谢您的友好评论,我已经这样做了,现在工作正常。由于这个name="EmployeeContact[@(Model.RecordId)].ContactDescription",它不起作用,我使用的是name="model[@(Model.RecordId)].ContactDescription",因此使用属性名称有助于模型绑定器了解如何将哪些元素与哪些属性相关联。我为此苦苦挣扎了一整天,甚至出现了一种令人痛苦的头痛,我现在正在护理。
  • 我正在使用public string RecordId { get; set; } = Guid.NewGuid().ToString(); 生成一个索引器,它的工作原理就像魅力一样,这解释了这行代码new ContactDetailViewModel()
猜你喜欢
  • 2013-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多