ASP.NET 包含对象列表的对象的 Core 3.0 MVC CRUD
ASP.NET Core 3.0 MVC CRUD for object that contains list of objects
我有以下 类:
public class Folder
{
public Folder()
{
Documents = new List<Document>()
}
public string Name { get; set; }
public List<Document> Documents { get; set; }
}
和:
public class Document
{
public string Name { get; set; }
public string Path { get; set; }
}
我需要一个 razor 视图,其中的表单将在提交后保存一个新的 Folder
。除了 Name
字段之外,我希望表单还包含 Document
的 table 和一个添加按钮。我希望能够通过按下按钮向 table 添加行(文档)。换句话说,我想动态添加 rows/documents 。按下按钮后,应该会出现一个带有输入字段的新行,供用户填写。用户提交表单后,提交的模型应包含列表中与 table.
行一样多的 Document 对象
您可以在下面找到我到目前为止尝试过的内容。如果有人有更优雅的解决方案,我们非常欢迎!
1) 我尝试搭建局部视图,如下所示,但随后按钮调用了一个新操作。理想情况下,我不想离开屏幕。我希望能够动态添加行,并在我点击提交时将这些 rows/documents 发回我的模型中。生成的文件如下:
@model IEnumerable<Document>
<p>
<div class="form-group">
<div class="col-md-offset-2 col-md-10 text-right">
<a asp-action="GetNewDocument" class="btn btn-primary">Add Document</a>
</div>
</div>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Name)
</th>
<th>
@Html.DisplayNameFor(model => model.Path)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Path)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) |
@Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) |
@Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
</td>
</tr>
}
</tbody>
</table>
2) 我尝试使用编辑器模板并 Ajax 调用控制器操作以返回新创建文档的部分视图,但是当我提交表单时,文件夹似乎没有文档任何。更具体地说,我有:
AddFolder.cshtml:
@model Folder
<div>
<h3>Add Folder</h3>
<input id="add-document" type="button" value="Add Document" class="btn btn-primary" />
</div>
<form asp-controller="Folder" asp-action="AddFolder" method="post" role="form">
<div class="form-group form-row">
<label asp-for="Name"></label>
<input asp-for="Name" type="text" />
</div>
div class="form-group form-row">
<table class="table table-hover" id="documentsTable">
<thead>
<tr>
<th scope="col">
DOCUMENT NAME
</th>
<th scope="col">
DOCUMENT PATH
</th>
</tr>
</thead>
<tbody>
@Html.EditorFor(m => m.Documents)
</tbody>
</table>
</div>
</form>
<script type="text/javascript">
$(document).ready(function () {
$("#add-document").click(function () {
$.ajax({
url: "GetNewDocument",
success: function (data) {
$("#documentsTable").append(data);
}
});
});
});
</script>
控制器中的 GetNewDocument 操作方法如下所示:
public PartialViewResult GetNewDocument()
{
return PartialView("NewDocument", new Document());
}
NewDocument部分视图:
@model Document
@Html.EditorForModel()
和 EditorTemplates 文件夹中的Document.cshtml:
@model Document
<tr class="document-row">
@{
using (Html.BeginCollectionItem("Documents"))
{
<td>
@Html.TextBoxFor(m => m.Name)
@Html.ValidationMessageFor(m => m.Name)
</td>
<td>
@Html.TextBoxFor(m => m.Path)
@Html.ValidationMessageFor(m => m.Path)
</td>
}
}
</tr>
在这一点上,我什至不确定这是否是我在 Asp.Net Core 中做我想做的事情的正确方法。
但我很确定我遗漏了一些东西,因为没有 Document
回发并且列表为空。
欢迎任何帮助。
提前谢谢你。
- 尝试使用
IList<Document>
作为模型(而不是 IEnumerable<Document>
)。
枚举时,使用标准for each
循环:
@for (var i=0; i < Model.Count; i++)
{
var listIdx = i; // Some hack since there is a caveat with i (can't remember)
var modelItem = Model[listIdx];
<tr>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Path)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) |
@Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) |
@Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
</td>
</tr>
}
我找到了解决方法。
AddFolder.cshtml应该有:
<tbody>
@{
for (int i = 0; i < Model.Documents?.Count(); i++)
{
@Html.EditorFor(m => m.Documents[i])
}
}
</tbody>
而不是:
<tbody>
@Html.EditorFor(m => m.Documents)
</tbody>
在控制器中,处理提交模型的动作应该有一个额外的参数:
[HttpPost]
public IActionResult AddFolder(Folder model, IEnumerable<Document> Documents)
{
model.Documents = Documents;
if (!ModelState.IsValid) {
return View(model);
}
// Persist to db here
// RedirectToAction or whatever after
}
奖金信息:
如果您需要自定义验证,您将需要每个对象的标识 ID,以便您可以为 AddModelError
方法生成正确的密钥。
检查 post 的答案以了解原因。
为此,您只需包含一个附加参数 IFormCollection form
并获得 id
,如下所示:
foreach (var id in form.FirstOrDefault(f => f.Key == "Documents.index").Value)
{
// Do what you need to do here
}
我有以下 类:
public class Folder
{
public Folder()
{
Documents = new List<Document>()
}
public string Name { get; set; }
public List<Document> Documents { get; set; }
}
和:
public class Document
{
public string Name { get; set; }
public string Path { get; set; }
}
我需要一个 razor 视图,其中的表单将在提交后保存一个新的 Folder
。除了 Name
字段之外,我希望表单还包含 Document
的 table 和一个添加按钮。我希望能够通过按下按钮向 table 添加行(文档)。换句话说,我想动态添加 rows/documents 。按下按钮后,应该会出现一个带有输入字段的新行,供用户填写。用户提交表单后,提交的模型应包含列表中与 table.
您可以在下面找到我到目前为止尝试过的内容。如果有人有更优雅的解决方案,我们非常欢迎!
1) 我尝试搭建局部视图,如下所示,但随后按钮调用了一个新操作。理想情况下,我不想离开屏幕。我希望能够动态添加行,并在我点击提交时将这些 rows/documents 发回我的模型中。生成的文件如下:
@model IEnumerable<Document>
<p>
<div class="form-group">
<div class="col-md-offset-2 col-md-10 text-right">
<a asp-action="GetNewDocument" class="btn btn-primary">Add Document</a>
</div>
</div>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Name)
</th>
<th>
@Html.DisplayNameFor(model => model.Path)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Name)
</td>
<td>
@Html.DisplayFor(modelItem => item.Path)
</td>
<td>
@Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) |
@Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) |
@Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })
</td>
</tr>
}
</tbody>
</table>
2) 我尝试使用编辑器模板并 Ajax 调用控制器操作以返回新创建文档的部分视图,但是当我提交表单时,文件夹似乎没有文档任何。更具体地说,我有:
AddFolder.cshtml:
@model Folder
<div>
<h3>Add Folder</h3>
<input id="add-document" type="button" value="Add Document" class="btn btn-primary" />
</div>
<form asp-controller="Folder" asp-action="AddFolder" method="post" role="form">
<div class="form-group form-row">
<label asp-for="Name"></label>
<input asp-for="Name" type="text" />
</div>
div class="form-group form-row">
<table class="table table-hover" id="documentsTable">
<thead>
<tr>
<th scope="col">
DOCUMENT NAME
</th>
<th scope="col">
DOCUMENT PATH
</th>
</tr>
</thead>
<tbody>
@Html.EditorFor(m => m.Documents)
</tbody>
</table>
</div>
</form>
<script type="text/javascript">
$(document).ready(function () {
$("#add-document").click(function () {
$.ajax({
url: "GetNewDocument",
success: function (data) {
$("#documentsTable").append(data);
}
});
});
});
</script>
控制器中的 GetNewDocument 操作方法如下所示:
public PartialViewResult GetNewDocument()
{
return PartialView("NewDocument", new Document());
}
NewDocument部分视图:
@model Document
@Html.EditorForModel()
和 EditorTemplates 文件夹中的Document.cshtml:
@model Document
<tr class="document-row">
@{
using (Html.BeginCollectionItem("Documents"))
{
<td>
@Html.TextBoxFor(m => m.Name)
@Html.ValidationMessageFor(m => m.Name)
</td>
<td>
@Html.TextBoxFor(m => m.Path)
@Html.ValidationMessageFor(m => m.Path)
</td>
}
}
</tr>
在这一点上,我什至不确定这是否是我在 Asp.Net Core 中做我想做的事情的正确方法。
但我很确定我遗漏了一些东西,因为没有 Document
回发并且列表为空。
欢迎任何帮助。 提前谢谢你。
- 尝试使用
IList<Document>
作为模型(而不是IEnumerable<Document>
)。 枚举时,使用标准
for each
循环:@for (var i=0; i < Model.Count; i++) { var listIdx = i; // Some hack since there is a caveat with i (can't remember) var modelItem = Model[listIdx]; <tr> <td> @Html.DisplayFor(modelItem => item.Name) </td> <td> @Html.DisplayFor(modelItem => item.Path) </td> <td> @Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) | @Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) | @Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ }) </td> </tr> }
我找到了解决方法。
AddFolder.cshtml应该有:
<tbody>
@{
for (int i = 0; i < Model.Documents?.Count(); i++)
{
@Html.EditorFor(m => m.Documents[i])
}
}
</tbody>
而不是:
<tbody>
@Html.EditorFor(m => m.Documents)
</tbody>
在控制器中,处理提交模型的动作应该有一个额外的参数:
[HttpPost]
public IActionResult AddFolder(Folder model, IEnumerable<Document> Documents)
{
model.Documents = Documents;
if (!ModelState.IsValid) {
return View(model);
}
// Persist to db here
// RedirectToAction or whatever after
}
奖金信息:
如果您需要自定义验证,您将需要每个对象的标识 ID,以便您可以为 AddModelError
方法生成正确的密钥。
检查 IFormCollection form
并获得 id
,如下所示:
foreach (var id in form.FirstOrDefault(f => f.Key == "Documents.index").Value)
{
// Do what you need to do here
}