ASP.NET MVC:动态添加部分视图并将它们反映在视图模型中
Posted
技术标签:
【中文标题】ASP.NET MVC:动态添加部分视图并将它们反映在视图模型中【英文标题】:ASP.NET MVC: Adding partial views dynamically and having them reflected in the view model 【发布时间】:2019-05-23 15:23:27 【问题描述】:情况:我有一个由部分组成的 ASP.NET Razor 页面。
其中一些在循环中迭代作为主页视图模型成员的集合。这些迭代的部分使用集合的成员类型作为它们自己的视图模型。
所以 Razor 的主页看起来像这样:
@model MyProject.MainViewModel
@*Other stuff...*@
@foreach (Subtype v in Model.SubViewModel)
html.RenderPartial("MyPartial", v);
部分看起来像这样:
@model Subtype
@Html.HiddenFor(t=>t.ParentViewModelID)
@Html.EditorFor(t=>t.Field1)
@Html.EditorFor(t=>t.Field2)
这一切都适用于初始页面加载,但我想知道我应该如何处理通过 AJAX 动态添加这些部分。
假设用户按下一个按钮,该按钮最终旨在添加到这些视图模型集合之一。我可以 AJAX 回到服务器,在那里渲染适当的部分,然后返回给客户端:
[System.Web.Mvc.HttpGet]
public ActionResult AddSubtype(int mainViewModelId)
var model = new Sub ParentViewModelID=mainViewModelId;
return PartialView("MyPartial", model);
然后我使用一些脚本将其粘贴到它所属的 DOM 中:
success: (data) => $('#subtypeHanger').append(data);,
这似乎可行,除了一个很大的部分:当我最终提交表单时,我没有在我的视图模型中看到与这个动态添加的部分相关的数据。
我一直在尝试对此进行调试,但我想从广义上讲这是否可能 - 或者说,有多少 MVC 应该对这些东西进行抽象。显然我可以用 javascript 来强制它工作。不过,有没有我应该模仿的 ASP.NET MVC 模式?
编辑:我会提到一些我在发布后尝试过的事情:
手动管理局部视图的编辑控件的“名称”和“ID”属性,这样它们最终看起来就像我将这些控件嵌套在主视图中而不是局部(即更长,包含更多文本和索引)。
对局部视图使用主视图模型类。这使我将循环移动到部分中。 “name”和“id”属性看起来就像我在上面的 #1 中想要的那样,但是这种设计极大地复杂化了从我的 AJAX 调用返回部分的过程。
使用“for”循环而不是“foreach”。就其本身而言,这并不能达到我想要的效果。
综上所述,如果 #1 或 #2 是我正在做的最好的模式,也许我可以做到这一点。
【问题讨论】:
动态添加的表单字段(t.Field1 等)的name
属性是什么。这就是模型绑定器用于在发布/提交时将数据绑定到您的视图模型的内容。看起来Model.SubViewModel
是一个列表,因此当它们被添加到循环中时,它们可能具有列表索引位置(即name="SubViewModel[0]_Field1"
),但是当您动态添加时,由于它不在列表中,因此呈现如下:@987654328 @ 所以当你提交时它没有正确映射
@zgood 谢谢,这是 100% 正确的:名称字段是简单的未索引值,例如“Field1”。所以我想这就是我需要攻击的。如果我将我的“for”循环移动到部分内部,我认为这可能会有所帮助......但是我不能真正动态地添加那个部分,因为它是针对整个集合的。我还需要另一个,最内心的部分吗?我需要以某种方式自己管理“名称”吗?谢谢!!
您正在动态添加它们,您是否还打算通过 ajax 调用动态删除它们?如果是这样,管理列表项索引可能会很烦人(即,如果 #2 被删除,则在 3 个列表中,则需要 SubViewModel[2]_Field1
来 SubViewModel[1]_Field1
才能正确绑定)。通常我发现这样做的最佳方法是创建一个循环通过inputs
的javascript 函数,并确保name
属性正确-具有正确的列表名称前缀(即SubViewModel
)并且索引正确。然后在每个 ajax 添加和删除操作后调用该函数
好的@zgood,这很有帮助。谢谢。
重要的是要意识到,当您提交 ajax 调用时,因为 mvc 是无状态的,因此 mvc 在此之前不知道服务器上的状态更改,因此 mvc 将无法返回正确的值对于名称属性
【参考方案1】:
“情况:我有一个由部分组成的 ASP.NET Razor 页面。”
这称为“主详细信息”
检查 Master Details CRUD with MVC 5 | The ASP.NET Forums诀窍是为您的字段命名
@Html.HiddenFor(t=>t.ParentViewModelID ,new htmlAttributes = new @Name = "[" + i + "].ParentViewModelID" )
@Html.EditorFor(t=>t.Field1 ,new htmlAttributes = new @Name = "[" + i + "].Field1" )
@Html.EditorFor(t=>t.Field2 , new htmlAttributes = new @Name = "[" + i + "].Field2" )
原来如此
<input type="text" name="[0].Field1" />
<input type="text" name="[0].Field2" />
<input type="text" name="[1].Field1" />
<input type="text" name="[1].Field2" />
如果你使用更好(对于 ASP.NET mvc 5 模型绑定)
public ActionResult Edit(MainViewModel master, List<Subtype> details)
如果您提供完整模型,我将提供完整的工作示例
【讨论】:
谢谢。似乎手动管理“名称”是做到这一点的唯一方法。不过,我自己并不能完全做到这一点,所以你的例子很有帮助。确认没有一些开箱即用的魔法可以解决这个问题也很好。 @user1172763 如果您提供完整模型,我将提供完整的工作示例以上是关于ASP.NET MVC:动态添加部分视图并将它们反映在视图模型中的主要内容,如果未能解决你的问题,请参考以下文章