C# 带有部分 CRUD 的 MVC 5 BeginCollectionItem

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29774822/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 04:17:14  来源:igfitidea点击:

MVC 5 BeginCollectionItem with Partial CRUD

c#asp.net-mvcrazor

提问by SelrekJohn

I have made changes below to the question, which is still the same but hopefully a lot clearer through the models and in regards to what I want to achieve and where I've come up against issues.

我已经对下面的问题进行了更改,这仍然是相同的,但希望通过模型和关于我想要实现的目标以及我遇到问题的地方更加清晰。

Below are shown two classes, Company and Employee, Company has a list of Employees.

下面显示了两个类,公司和员工,公司有一个员工列表。

This will be an input form so there will be no data in there to begin with.

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

Ultimately I want the user to be able to add as many Employee objects to the Company object model as they want and for the Employee objects to be updated

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

Am I on the right track with using BeginCollectionItem so I can add/remove as many Employee objects as I want? When I click on the Add button it takes it to the partial view on another page (with AjaxActionLink) but not with JavaScript.

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

UpdateRemoved AjaxActionLink and used JavaScript instead.

更新删除了 AjaxActionLink 并改用 JavaScript。

Index

指数

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

<h2>Company</h2>
<div>
    @Html.LabelFor(m => m.Name)
    @Html.EditorFor(m => m.Name)
</div>
<fieldset>
    <legend>Employees</legend>
    <div id="new-Employee">
        @foreach (var Employee in Model.Employees)
        {
            Html.RenderPartial("_Employee", Employee);
        }
    </div>
    <div>
        <input type="button" id="addemployee" name="addemployee" value="Add Employee"/>
        <br/>
    </div>
    <br/>
    @section Scripts
    {
        <script type="text/javascript">
            $('#addemployee').on('click', function () {
                $.ajax({
                    async: false,
                    url: '/Company/AddNewEmployee'
                }).success(function (partialView) {
                    $('#new-Employee').append(partialView);
                });
            });
        </script>
    }
</fieldset>
<div>
    <input type="submit" value="Submit" />
</div>

_Employee PartialView

_员工局部视图

    @model MvcTest.Models.Employee

@using (Html.BeginCollectionItem("Employees"))
{
    <div class="employeeRow">
        @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)

        <a href="#" class="deleteRow">Delete</a>
    </div>
}

@section Scripts
{
$("a.deleteRow").live("click", function(){
    $(this).parents("div.employeeRow:first").remove();
return false;
});
}

Controller

控制器

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);
        }
    }

Model

模型

public class Company
    {
        [Key]
        public int Id { get; set; }
        [Display(Name = "Company")]
        public string Name { get; set; }
        public List<Employee> Employees { get; set; }

        //public Company()
        //{
        //    Employees = new List<Employee>
        //    {
        //        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;}
    }

采纳答案by PurpleSmurph

You do not need to use BeginCollectionItem in order to achieve this. From having to look into it myself and trying to use it for a similar issue, it appears it was created for problems of this nature with earlier versions of MVC.

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

Use Partial Views to display and update the list. One partial view to display and iterate through the list of objects, and another to create a new object which upon post back to update the list will show the newly created object in the partial view with the list.

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

I posted a similar question on here which should solve your issue, click here

我在这里发布了一个类似的问题,应该可以解决您的问题,请单击此处

Hope this helps.

希望这可以帮助。

UpdateThe reason your delete doesn't work is because you can't call JS from Partial View, put it in the main view (@section Script). Also I think you got a bit muddled with your class and id keywords in your divs, have a look below.

更新你的delete不行的原因是你不能从Partial View调用JS,把它放在主视图(@section Script)。此外,我认为您对 div 中的 class 和 id 关键字有些困惑,请看下面。

So you should have:

所以你应该有:

Partial View

局部视图

@model MvcTest.Models.Employee
    @using (Html.BeginCollectionItem("Employees"))
    {
        <div id="employeeRow" class="employeeRow">
            @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)

            <a href="#" id="deleteRow" class="deleteRow" onclick="deleteFunction()">Delete</a>
        </div>
    }

Main View

主视图

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

<h2>Company</h2>
<div>
    @Html.LabelFor(m => m.Name)
    @Html.EditorFor(m => m.Name)
</div>
<fieldset>
    <legend>Employees</legend>
    <div id="new-Employee">
        @foreach (var Employee in Model.Employees)
        {
            Html.RenderPartial("_Employee", Employee);
        }
    </div>
    <div>
        <input type="button" id="addemployee" name="addemployee" value="Add Employee"/>
        <br/>
    </div>
    <br/>
    @section Scripts
    {
        <script type="text/javascript">
            $('#addemployee').on('click', function () {
                $.ajax({
                    async: false,
                    url: '/Company/AddNewEmployee'
                }).success(function (partialView) {
                    $('#new-Employee').append(partialView);
                });
            });

            $("#deleteRow").live("click", function () {
                $(this).parents("#employeeRow:first").remove();
                return false;
            });
        </script>
    }
</fieldset>
<div>
    <input type="submit" value="Submit" />
</div>

回答by Gone Coding

Treat the views as independent. If your partial view was a full view, you would pass it a IEnumerable<ClassB>

将视图视为独立的。如果您的局部视图是完整视图,则将其传递给IEnumerable<ClassB>

so render with:

所以渲染:

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

Also, you can't use foreachwith EditorForas there is insufficient information to create a name based on the index. Use a normal for loop instead. The expression parser can then convert it to name="name[1]"etc as the index is available in the expression:

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

@model IEnumerable<Project.Models.ClassB>

@if(Model != null)
{
    for (int i = 0; i < Model.Count; i++)
    {
    <tr>
        <td>
            @Html.EditorFor(modelItem => Model[i].Name)
            <input type="button" value="Clear" />
            <input type="submit" value="Create" />
        </td>
    </tr>
    }
}

There is more missing from your example (what Clearand Createconnect to for instance), so if you can provide the rest of your controller code I will expand this.

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

回答by Ala

You can use (EditorTemplates) to view (ClassB) as following:

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

1- Create folder named (EditorTemplates) under the (Views/Home) folder (Assuming your controller name is Home):

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

2- Under the created (EditorTemplates) folder, create a view named (ClassB)

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

enter image description here

在此处输入图片说明

and add the following template for the (ClassB) view:

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

@model Project.Models.ClassB
@if(Model != null)
{

    <tr>
        <td>
            @Html.EditorFor(modelItem => Model.Name)
            <input type="button" value="Clear" />
            <input type="submit" value="Create" />
        </td>
    </tr>

}

and (ClassAView) should be as following:

和 (ClassAView) 应如下所示:

@model Project.Models.ClassA

<tr>
<td>
@Html.EditorFor(m => m.name)
</td>
<td>
@Html.EditorFor(m => m.classB);
</td>
</tr>

The editor will automatically iterate through the list of objects rendering the view for each of them.

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

回答by Dawood Awan

Lets say ClassAis your ViewModel:

让我们说ClassA是你的 ViewModel:

You only need one Partial View or View to Update both:

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

e.g. Edit.cshtml

例如 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)
<button type="button"> Add </button>
<button type="button"> Remove </button>
}

<input type="submit"  value = "save"/>

}

Note: In your Partial view you are using foreach loop, The MVC Model Binder Requires the Input fields to be in the format:

注意:在您使用 foreach 循环的 Partial 视图中,MVC 模型绑定器要求输入字段采用以下格式:

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

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

So for this we use for loop

所以为此我们使用 for 循环

Then in controller:

然后在控制器中:

[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);
}

If you want to dynamically Add or Remove Items from the List:

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

Create another Partial View classBs:

创建另一个局部视图classBs

        @model List<classB>
        <div id="lists">
            foreach (var contact in Model)
            {
               @Html.Partial("ClassBRow", contact)
            }
    </div>

<button data-action-url="@Url.Action("ClassBRow","CONTROLLER")" class="btn btn-primary pull-right" id="addItem">Add</button>

<script>
 $("#addItem").click(function () {
            var btn = $(this);
            $.ajax({
                url: btn.data('action-url'),
                success: function (html) {
                    $("#lists").append(html);
                }
            });
            return false;
        });

</script>

Create another Partial View: ClassBRow.cshtml:

创建另一个局部视图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" })

<span class="glyphicon glyphicon-trash" data-action="removeItem" title="remove" style="cursor:pointer"></span>

    }

In your controller:

在您的控制器中:

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

AND Edit.cshtml becomes:

AND Edit.cshtml 变为:

    @model ClassA

    @Html.BeginForm(){

    @Html.TextBoxFor(m => m.name)

@Html.Partial("classBs", model.classB)

    <input type="submit"  value = "save"/>

    }