如何使用 Razor 和 .NET Core 将项目添加到 ViewModel 中的列表?
How to add an item to a list in a ViewModel using Razor and .NET Core?
这是我的情况。
假设我有一个名为 TheView.cshtml.
的视图 TheView.cshtml
有一个名为 TheViewModel.cs
的 ViewModel。在 TheViewModel.cs
中,驻留了一个名为 TheObjectList
.
的对象 (TheObject
) 的列表
我有一个 TheObject
的编辑器模板,名为 TheObject.cshtml
。使用这个编辑器模板,我可以简单地用 @Html.EditorFor(model => model.TheObjectList)
.
显示 TheObjectList
中的所有项目
但是,现在我想动态地将对象添加到这个列表中。我有一个 AJAX 函数,它调用一个简单的部分视图给用户一个空白行来添加一个新的“TheObject
”,但是,我动态添加的任何新的 TheObject
都不被考虑部分原文TheObjectList
.
这是因为原始 TheObjectList
中的每个项目都是根据其在原始列表中的索引创建的,并带有特定的前缀,而每个新的动态 TheObject 都是在没有前缀的情况下创建的,因此 Razor 看不到它作为列表的一部分。
有办法解决这个问题吗?
TheView.cshtml
@model Models.ViewModels.TheViewModel
<table id="Table">
<tbody>
@Html.EditorFor(m => m.TheObjectList);
</tbody>
</table>
<button id="AddObject" type="button" class="btn btn-primary">Add Object</button>
TheViewModel.cs
public class TheViewModel
{
public List<TheObject> TheObjectList { get; set; }
}
AddObject 控制器方法
public IActionResult AddObject()
{
return PartialView("_EmptyRow", new TheObject());
}
AJAX 添加对象的方法
$('#AddObject').click(function () {
$.ajax({
url: 'AddObject',
cache: false,
success: function (data) {
$('#Table > tbody').append(data);
},
error: function (a, b, c) {
alert(a + " " + b + " " + c);
}
});
});
您基本上需要 generate/return 标记,它看起来与编辑器模板为您的表单字段生成的标记相同,除了元素索引。您需要从客户端传递索引,这将成为表单字段名称的一部分。
假设您的编辑器模板如下所示,并且您的 TheObject 有一个 GroupName
属性
@model TheObject
<div>
@Html.HiddenFor(x => x.GroupName)
@Html.TextBoxFor(s=>s.GroupName,new {@class="thingRow"})
</div>
现在,当您使用当前代码呈现页面时,编辑器模板将生成这样的输入字段
<input class="thingRow" id="TheObjectList_0__GroupName"
name="TheObjectList[0].GroupName" type="text" value="Something">
其中 0
将替换为您的 TheObjectList
collection.
中项目的索引
现在假设您在 collection 中已经有 5 个项目,因此当用户单击添加按钮时,您希望生成像上面那样的标记,除了 0
将替换为 5
(第六项)。因此,让我们更新 ajax 调用以包含当前的项目数。
$('#AddObject').click(function () {
var i = $(".thingRow").length;
$.ajax({
url: 'AddObject?index=' + i,
success: function (data) {
$('#Table > tbody').append(data);
},
error: function (a, b, c) {
console.log(a, b, c);
}
});
});
这意味着,我们需要在我们的操作方法中接受索引值。由于我们需要将此索引值从操作方法传递到我们的视图以构建输入字段名称值,因此我向您的 class 添加了一个 属性 称为 Index
public ActionResult AddObject(int index)
{
return PartialView("_EmptyRow", new TheObject { Index = index});
}
现在在您的 _EmptyRow 部分视图中,
@model TheObject
<input id="TheObjectList_@(Model.Index)__GroupName"class="thingRow"
name="TheObjectList[@(Model.Index)].GroupName" type="text" value=""/>
现在,当您提交表单时,模型绑定将适用于这些动态添加的项目,假设您的 Table 位于表单中。
@model TheViewModel
@using (Html.BeginForm())
{
<table id="Table">
<tbody>
@Html.EditorFor(m => m.TheObjectList);
</tbody>
</table>
<button id="AddObject" type="button" class="btn btn-primary">Add Object</button>
<button type="submit" class="btn btn-primary">Save</button>
}
这是我的情况。
假设我有一个名为 TheView.cshtml.
的视图 TheView.cshtml
有一个名为 TheViewModel.cs
的 ViewModel。在 TheViewModel.cs
中,驻留了一个名为 TheObjectList
.
TheObject
) 的列表
我有一个 TheObject
的编辑器模板,名为 TheObject.cshtml
。使用这个编辑器模板,我可以简单地用 @Html.EditorFor(model => model.TheObjectList)
.
TheObjectList
中的所有项目
但是,现在我想动态地将对象添加到这个列表中。我有一个 AJAX 函数,它调用一个简单的部分视图给用户一个空白行来添加一个新的“TheObject
”,但是,我动态添加的任何新的 TheObject
都不被考虑部分原文TheObjectList
.
这是因为原始 TheObjectList
中的每个项目都是根据其在原始列表中的索引创建的,并带有特定的前缀,而每个新的动态 TheObject 都是在没有前缀的情况下创建的,因此 Razor 看不到它作为列表的一部分。
有办法解决这个问题吗?
TheView.cshtml
@model Models.ViewModels.TheViewModel
<table id="Table">
<tbody>
@Html.EditorFor(m => m.TheObjectList);
</tbody>
</table>
<button id="AddObject" type="button" class="btn btn-primary">Add Object</button>
TheViewModel.cs
public class TheViewModel
{
public List<TheObject> TheObjectList { get; set; }
}
AddObject 控制器方法
public IActionResult AddObject()
{
return PartialView("_EmptyRow", new TheObject());
}
AJAX 添加对象的方法
$('#AddObject').click(function () {
$.ajax({
url: 'AddObject',
cache: false,
success: function (data) {
$('#Table > tbody').append(data);
},
error: function (a, b, c) {
alert(a + " " + b + " " + c);
}
});
});
您基本上需要 generate/return 标记,它看起来与编辑器模板为您的表单字段生成的标记相同,除了元素索引。您需要从客户端传递索引,这将成为表单字段名称的一部分。
假设您的编辑器模板如下所示,并且您的 TheObject 有一个 GroupName
属性
@model TheObject
<div>
@Html.HiddenFor(x => x.GroupName)
@Html.TextBoxFor(s=>s.GroupName,new {@class="thingRow"})
</div>
现在,当您使用当前代码呈现页面时,编辑器模板将生成这样的输入字段
<input class="thingRow" id="TheObjectList_0__GroupName"
name="TheObjectList[0].GroupName" type="text" value="Something">
其中 0
将替换为您的 TheObjectList
collection.
现在假设您在 collection 中已经有 5 个项目,因此当用户单击添加按钮时,您希望生成像上面那样的标记,除了 0
将替换为 5
(第六项)。因此,让我们更新 ajax 调用以包含当前的项目数。
$('#AddObject').click(function () {
var i = $(".thingRow").length;
$.ajax({
url: 'AddObject?index=' + i,
success: function (data) {
$('#Table > tbody').append(data);
},
error: function (a, b, c) {
console.log(a, b, c);
}
});
});
这意味着,我们需要在我们的操作方法中接受索引值。由于我们需要将此索引值从操作方法传递到我们的视图以构建输入字段名称值,因此我向您的 class 添加了一个 属性 称为 Index
public ActionResult AddObject(int index)
{
return PartialView("_EmptyRow", new TheObject { Index = index});
}
现在在您的 _EmptyRow 部分视图中,
@model TheObject
<input id="TheObjectList_@(Model.Index)__GroupName"class="thingRow"
name="TheObjectList[@(Model.Index)].GroupName" type="text" value=""/>
现在,当您提交表单时,模型绑定将适用于这些动态添加的项目,假设您的 Table 位于表单中。
@model TheViewModel
@using (Html.BeginForm())
{
<table id="Table">
<tbody>
@Html.EditorFor(m => m.TheObjectList);
</tbody>
</table>
<button id="AddObject" type="button" class="btn btn-primary">Add Object</button>
<button type="submit" class="btn btn-primary">Save</button>
}