具有部分CRUD的MVC 5 BeginCollectionItem

我在下面对这个问题进行了修改,这个问题仍然是一样的,但希望通过模型以及我想要实现的目标以及我遇到问题的方式更加清晰。

下面显示了两个类,Company和Employee,Company有一个Employees列表。

这将是一个输入表单,因此开始时将没有数据。

最终,我希望用户能够根据需要向Company对象模型添加尽可能多的Employee对象,并更新Employee对象

我是否使用BeginCollectionItem在正确的轨道上,所以我可以添加/删除尽可能多的Employee对象? 当我单击Add按钮时,它会将其带到另一个页面上的部分视图(使用AjaxActionLink),但不能使用JavaScript。

更新删除了AjaxActionLink并改为使用JavaScript。

指数

@model MvcTest.Models.Company @{ ViewBag.Title = "Index"; Layout = "~/Views/Shared/_Layout.cshtml"; } 

Company

@Html.LabelFor(m => m.Name) @Html.EditorFor(m => m.Name)
Employees
@foreach (var Employee in Model.Employees) { Html.RenderPartial("_Employee", Employee); }


@section Scripts { $('#addemployee').on('click', function () { $.ajax({ async: false, url: '/Company/AddNewEmployee' }).success(function (partialView) { $('#new-Employee').append(partialView); }); }); }

_Employee PartialView

  @model MvcTest.Models.Employee @using (Html.BeginCollectionItem("Employees")) { 
@Html.LabelFor(m => m.Name) @Html.EditorFor(m => m.Name) @Html.LabelFor(m => m.Telephone) @Html.EditorFor(m => m.Telephone) @Html.LabelFor(m => m.Mobile) @Html.EditorFor(m => m.Mobile) @Html.LabelFor(m => m.JobTitle) @Html.EditorFor(m => m.JobTitle) Delete
} @section Scripts { $("a.deleteRow").live("click", function(){ $(this).parents("div.employeeRow:first").remove(); return false; }); }

调节器

 public class CompanyController : Controller { // GET: Company public ActionResult Index() { var newCompany = new Company(); return View(newCompany); } public ActionResult AddNewEmployee() { var employee = new Employee(); return PartialView("_Employee", employee); } } 

模型

 public class Company { [Key] public int Id { get; set; } [Display(Name = "Company")] public string Name { get; set; } public List Employees { get; set; } //public Company() //{ // Employees = new List // { // new Employee{ Name = "Enter name"} // }; //} } public class Employee { [Key] public int Id { get; set; } [Display(Name="Employee")] public string Name { get; set; } public string Telephone { get; set; } public string Mobile {get;set;} [Display(Name="Job Title")] public string JobTitle {get;set;} } 

您不需要使用BeginCollectionItem来实现此目的。 从必须自己查看并尝试将其用于类似的问题,它似乎是为早期版本的MVC创建的这种性质的问题。

使用部分视图显示和更新列表。 一个局部视图用于显示和遍历对象列表,另一个用于创建一个新对象,该对象在回发后更新列表将在列表的局部视图中显示新创建的对象。

我在这里发布了一个类似的问题,可以解决你的问题, 点击这里

希望这可以帮助。

更新删除不起作用的原因是因为您无法从Partial View调用JS,将其放在主视图中(@section Script)。 另外我觉得你的div中的class和id关键字有点混乱,看看下面。

所以你应该:

部分视图

 @model MvcTest.Models.Employee @using (Html.BeginCollectionItem("Employees")) { 
@Html.LabelFor(m => m.Name) @Html.EditorFor(m => m.Name) @Html.LabelFor(m => m.Telephone) @Html.EditorFor(m => m.Telephone) @Html.LabelFor(m => m.Mobile) @Html.EditorFor(m => m.Mobile) @Html.LabelFor(m => m.JobTitle) @Html.EditorFor(m => m.JobTitle) Delete
}

主视图

  @model MvcTest.Models.Company @{ ViewBag.Title = "Index"; Layout = "~/Views/Shared/_Layout.cshtml"; } 

Company

@Html.LabelFor(m => m.Name) @Html.EditorFor(m => m.Name)
Employees
@foreach (var Employee in Model.Employees) { Html.RenderPartial("_Employee", Employee); }


@section Scripts { }

让我们说ClassA是你的ViewModel:

您只需要一个部分视图或视图来更新两者:

例如Edit.cshtml

 @model ClassA @Html.BeginForm(){ @Html.TextBoxFor(m => m.name) for(int i = 0; i< Model.classB.Count; i++){ @Html.TextBoxFor(m => Model.classB[i].name)   }  } 

注意:在Partial视图中,您使用的是foreach循环,MVC Model Binder要求Input字段的格式为:

 list[0].prop1 list[0].prop2 list[0].prop3 list[1].prop1 list[1].prop2 list[1].prop3 

所以为此我们使用for循环

然后在控制器中:

 [HttpPost] public ActionResult Edit(ClassA model){ // HEre you will see model.ClassB list // you can then save them one by one foreach(var item in Model.classB){ save } return View(model); } 

如果要从列表中动态添加或删除项目:

创建另一个部分视图classBs

  @model List 
foreach (var contact in Model) { @Html.Partial("ClassBRow", contact) }

创建另一个局部视图: ClassBRow.cshtml

 @model classB using (Html.BeginCollectionItem("classB")) { @Html.HiddenFor(m => m.isDeleted, new { data_is_deleted = "false" }) @Html.TextBoxFor(m => Model.name, new { @class = "form-control" })  } 

在你的控制器中:

 public ActionResult ClassBRow() { return PartialView(new classB()); } 

AND Edit.cshtml变为:

  @model ClassA @Html.BeginForm(){ @Html.TextBoxFor(m => m.name) @Html.Partial("classBs", model.classB)  } 

将观点视为独立的。 如果您的局部视图是完整视图,您将传递一个IEnumerable

所以呈现:

  @Html.Partial("ClassBView", Model.ClassB) 

此外,您不能将foreachEditorFor一起使用,因为没有足够的信息来根据索引创建名称。 请使用普通for循环。 然后,表达式解析器可以将其转换为name="name[1]"等,因为索引在表达式中可用:

 @model IEnumerable @if(Model != null) { for (int i = 0; i < Model.Count; i++) {   @Html.EditorFor(modelItem => Model[i].Name)     } } 

您的示例中有更多缺失(例如, ClearCreate连接到什么),因此如果您可以提供其余的控制器代码,我将扩展它。

您可以使用(EditorTemplates)查看(ClassB),如下所示:

1-在(Views / Home)文件夹下创建名为(EditorTemplates)的文件夹(假设您的控制器名称为Home):

2-在创建的(EditorTemplates)文件夹下,创建一个名为(ClassB)的视图

在此处输入图像描述

并为(ClassB)视图添加以下模板:

 @model Project.Models.ClassB @if(Model != null) {   @Html.EditorFor(modelItem => Model.Name)     } 

和(ClassAView)应如下:

 @model Project.Models.ClassA   @Html.EditorFor(m => m.name)   @Html.EditorFor(m => m.classB);   

编辑器将自动遍历对象列表,为每个对象呈现视图。