MVC 5 动态行与 BeginCollectionItem [英] MVC 5 Dynamic Rows with BeginCollectionItem

查看:22
本文介绍了MVC 5 动态行与 BeginCollectionItem的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

单击按钮时向表格添加/删除行的最佳方法是什么?我需要从 ChildClass 属性创建的行(子类是主类/模型中的一个列表).

当前有一个视图(模型是 MyMain),它使用 RenderPartial 引用了一个局部视图.

局部视图显示模型的属性,一个名为 MyChild 的类,它是 MyMain 中的一个对象列表.

我想要添加和删除按钮来动态添加分部视图中保存的行.

因此重复添加 MyChild 以获取列表中的更多行.这可能吗?或者我不应该为此使用部分视图?

更新代码

以下是我正在使用的当前类和视图,我一直在尝试实现 BeginCollectionItem 帮助器,但我在尝试加载部分视图时得到了 null ref,尽管 if 语句说要创建如果不存在子类的新实例 - 为什么会忽略它?

主视图

 @using (Html.BeginForm()){<表格><tr><th>MyMain First</th><th>MyChild First</th></tr><tr><td>@Html.EditorFor(m => m.First)</td><td>@if (Model.child != null){for (int i = 0; i }

部分视图

@model MvcTest.Models.MyChild@using (Html.BeginCollectionItem("myChildren")){Html.EditorFor(m => m.Second);}

模型

公共类MyMain{[钥匙]公共 int Id { 获取;放;}公共字符串第一个{得到;放;}公共列表孩子{得到;放;}}公开课 MyChild{[钥匙]公共 int Id { 获取;放;}公共字符串第二{得到;放;}}

控制器

公共类 MyMainsController : 控制器{//获取:MyMains公共 ActionResult MyMainView(){返回视图();}[HttpPost]公共 ActionResult MyMainView(IEnumerable myChildren){返回视图(MyMainView",myChildren);}公共视图结果添加(){return View("MyChildView", new MyChild());}}

解决方案

更新的答案 - 原始代码对于动态"是真实的,但它允许一切我需要在问题参数内做.

最初,我无法在问题评论中得到斯蒂芬的 BCI 建议,从那时起我就得到了,而且非常棒.如果您复制+粘贴,更新部分中的以下代码将起作用,但您需要从 GIT 手动下载 BCI 或使用 PM>使用 Visual Studio 中的包管理器控制台安装包 BeginCollectionItem.

由于复杂性和之前没有做过 MVC,我在使用 BCI 的各个方面遇到了一些问题 - 这里是关于处理访问class.property(type class).property(type class).property的更多信息.

原始答案 - 我在下面给出了一个比我的问题更清楚的例子,这个例子很快就变得太混乱了.

使用两个部分视图,一个用于员工列表,另一个用于创建新员工,所有这些都包含在 companyemployee 的视图模型中,其中包含公司对象和员工对象列表.这样可以在列表中添加、编辑或删除多个员工.

希望这个答案能帮助任何人寻找类似的东西,这应该提供足够的代码来让它工作,并至少推动你朝着正确的方向前进.

我省略了我的上下文和初始化程序类,因为它们只适用于代码,如果需要,我可以添加它们.

感谢所有帮助过的人.

模型 - CompanyEmployee 作为视图模型

公共类公司{[钥匙]公共 int id { 获取;放;}[必需的]公共字符串名称 { 获取;放;}}公开课员工{[钥匙]公共 int id { 获取;放;}[必需的]公共字符串名称 { 获取;放;}[必需的]公共字符串职位{获取;放;}[必需的]公共字符串编号 { 获取;放;}[必需的]公共字符串地址 { 获取;放;}}公共类 CompanyEmployee{公众公司公司{得到;放;}公共列表<员工>员工{得到;放;}}

索引

@model MMV.Models.CompanyEmployee@{ViewBag.Title = "索引";布局 = "~/Views/Shared/_Layout.cshtml";}<h2>索引</h2><字段集><legend>公司</legend><table class="table"><tr><th>@Html.LabelFor(m => m.company.name)</th></tr><tr><td>@Html.EditorFor(m => m.company.name)</td></tr></fieldset><字段集><legend>员工</legend>@{Html.RenderPartial("_employeeList", Model.employees);}</fieldset><字段集>@{Html.RenderPartial("_employee", new MMV.Models.Employee());}</fieldset><div class="form-group"><div class="col-md-offset-2 col-md-10"><input type="submit" value="Submit" class="btn btn-default"/>

部分员工列表

@model IEnumerable@using (Html.BeginForm("员工")){<table class="table"><tr><th>名称</th><th>职称</th><th>数字</th><th>地址</th><th></th></tr>@foreach(模型中的 var emp){<tr><td>@Html.DisplayFor(modelItem => emp.name)</td><td>@Html.DisplayFor(modelItem => emp.jobtitle)</td><td>@Html.DisplayFor(modelItem => emp.number)</td><td>@Html.DisplayFor(modelItem => emp.address)</td><td><input type="submit" formaction="/Employees/Edit/@emp.id" value="Edit"/><input type="submit"formaction="/Employees/Delete/@emp.id" value="Remove"/></td></tr>}}

部分视图创建员工

@model MMV.Models.Employee@using (Html.BeginForm("Create","Employees")){<table class="table">@Html.ValidationSummary(true, "", new { @class = "text-danger" })<tr><td>@Html.EditorFor(model => model.name)@Html.ValidationMessageFor(model => model.name, "", new { @class = "text-danger" })</td><td>@Html.EditorFor(model => model.jobtitle)@Html.ValidationMessageFor(model => model.jobtitle)</td><td>@Html.EditorFor(model => model.number)@Html.ValidationMessageFor(model => model.number, "", new { @class = "text-danger" })</td><td>@Html.EditorFor(model => model.address)@Html.ValidationMessageFor(model => model.address, "", new { @class = "text-danger" })</td></tr><div class="form-group"><div class="col-md-offset-2 col-md-10"><input type="submit" value="Create" class="btn btn-default"/>

}

控制器 - 我用了多个,但你可以把它们都放在一个

public class CompanyEmployeeController : 控制器{私有 MyContext db = new MyContext();//GET: 公司员工公共 ActionResult 索引(){var newCompanyEmployee = new CompanyEmployee();newCompanyEmployee.employees = db.EmployeeContext.ToList();返回视图(新公司员工);}[HttpPost, ActionName("删除")]公共 ActionResult DeleteConfirmed(int id){雇员雇员 = db.EmployeeContext.Find(id);db.EmployeeContext.Remove(员工);db.SaveChanges();return RedirectToAction("Index", "CompanyEmployee");}[HttpPost]public ActionResult Create([Bind(Include = "id,name,jobtitle,number,address")] 员工雇员){如果(模型状态.IsValid){db.EmployeeContext.Add(员工);db.SaveChanges();return RedirectToAction("Index", "CompanyEmployee");}返回视图(员工);}}

更新代码 - 使用 BeginCollectionItem - 动态添加/删除

学生部分

@model UsefulCode.Models.Person<div class="editorRow">@using (Html.BeginCollectionItem("students")){<div class="ui-grid-c ui-responsive"><div class="ui-block-a"><跨度>@Html.TextBoxFor(m => m.firstName)</span>

<div class="ui-block-b"><跨度>@Html.TextBoxFor(m => m.lastName)</span>

<div class="ui-block-c"><跨度><span class="dltBtn"><a href="#" class="deleteRow">X</a></span></span>

}

教师部分

@model UsefulCode.Models.Person<div class="editorRow">@using (Html.BeginCollectionItem("teachers")){<div class="ui-grid-c ui-responsive"><div class="ui-block-a"><跨度>@Html.TextBoxFor(m => m.firstName)</span>

<div class="ui-block-b"><跨度>@Html.TextBoxFor(m => m.lastName)</span>

<div class="ui-block-c"><跨度><span class="dltBtn"><a href="#" class="deleteRow">X</a></span></span>

}

注册控制器

public ActionResult Index(){var 寄存器 = 新寄存器{学生 = 新列表<人>{新人 { firstName = "", lastName = "" }},教师 = 新列表<人>{新人 { lastName = "", firstName = "" }}};返回视图(注册);}

注册和人员模型

公共类注册{公共 int id { 获取;放;}公共列表<人>老师{得到;放;}公共列表<人>学生{得到;放;}}公开课人{公共 int id { 获取;放;}公共字符串 firstName { 获取;放;}公共字符串姓氏 { 获取;放;}}

索引

@{布局 = "~/Views/Shared/_Layout.cshtml";}@model UsefulCode.Models.Register<div id="studentList">@using (Html.BeginForm()){<div id="editorRowsStudents">@foreach(Model.students 中的 var 项目){@Html.Partial("StudentView", item)}

@Html.ActionLink("Add", "StudentManager", null, new { id = "addItemStudents", @class = "button" });}

<div id="teacherList">@using (Html.BeginForm()){<div id="editorRowsTeachers">@foreach(Model.teachers 中的 var 项目){@Html.Partial("TeacherView", item)}

@Html.ActionLink("Add", "TeacherManager", null, new { id = "addItemTeachers", @class = "button" });}

@section 脚本 {<script type="text/javascript">$(函数(){$('#addItemStudents').on('click', function () {$.ajax({url: '@Url.Action("StudentManager")',缓存:假,成功:函数(html){$(#editorRowsStudents").追加(html);}});返回假;});$('#editorRowsStudents').on('click', '.deleteRow', function () {$(this).closest('.editorRow').remove();});$('#addItemTeachers').on('click', function () {$.ajax({url: '@Url.Action("TeacherManager")',缓存:假,成功:函数(html){$(#editorRowsTeachers").附加(html);}});返回假;});$('#editorRowsTeachers').on('click', '.deleteRow', function () {$(this).closest('.editorRow').remove();});});}

StudentManager 操作:

public PartialViewResult StudentManager(){返回 PartialView(new Person());}

What is the best way to add/delete rows to a table when a button is clicked? I need rows created from ChildClass properties (child class is a list within the main class/model).

Currently have a View (model is MyMain) which references a Partial View using RenderPartial.

The partial view displays the properties of the model, a class called MyChild which is an object list within MyMain.

I want to have add and delete buttons to dynamically add the rows which are held within the partial view.

So adding MyChild repeatedly for more rows on the list. Is this possible? Or should I not be using partial views for this?

Updated Code

Below are the current classes and views I'm working with, I've been trying to implement the BeginCollectionItem helper but I'm getting null ref where I'm trying to load the partial view despite the if statement saying to create a new instance of the child class if doesn't exist - why is this being ignored?

Main View

    @using (Html.BeginForm())
{
    <table>
        <tr>
            <th>MyMain First</th>
            <th>MyChild First</th>
        </tr>
        <tr>
            <td>
                @Html.EditorFor(m => m.First)
            </td>
            <td>
                @if (Model.child != null)
                {
                    for (int i = 0; i < Model.child.Count; i++)
                    {
                        Html.RenderPartial("MyChildView");
                    }
                }        
                else
                {
                    Html.RenderPartial("MyChildView", new MvcTest.Models.MyChild());
                }       
            </td>
        </tr>
        @Html.ActionLink("Add another", "Add", null, new { id = "addItem" })
    </table>
}

Partial View

@model MvcTest.Models.MyChild

@using (Html.BeginCollectionItem("myChildren"))
{
    Html.EditorFor(m => m.Second);
}

Models

public class MyMain
{
    [Key]
    public int Id { get; set; }
    public string First { get; set; }
    public List<MyChild> child { get; set; }
}

public class MyChild
{
    [Key]
    public int Id { get; set; }
    public string Second { get; set; }
}

Controller

public class MyMainsController : Controller
{
    // GET: MyMains
    public ActionResult MyMainView()
    {
        return View();
    }

    [HttpPost]
    public ActionResult MyMainView(IEnumerable<MyChild> myChildren)
    {
        return View("MyMainView", myChildren);
    }

    public ViewResult Add()
    {
        return View("MyChildView", new MyChild());
    }
}

解决方案

Updated Answer - The original code is NOT true to 'dynamic', however it allows for everything I needed to do within the question parameters.

Initially, I couldn't get Stephen's BCI suggestion in the question comments working, since then I have and it's brilliant. The code below in the updated section will work if you copy + paste, but you will need to either manually download BCI from GIT or use PM> Install-Package BeginCollectionItem with Package Manager Console in Visual Studio.

I had some issue with various points using BCI due to the complexity and not having done MVC before - here is more information on dealing with accessing class.property(type class).property(type class).property.

Original answer - I've gone with a more clear example below than in my question which quickly got too confusing.

Using two partial views, one for the list of employees and another for the creation of a new employee all contained within the viewmodel of companyemployee which contains an object of company and a list of employee objects. This way multiple employees can be added, edited or deleted from the list.

Hopefully this answer will help anyone looking for something similar, this should provide enough code to get it working and at the very least push you in the right direction.

I've left out my context and initialiser classes as they're only true to code first, if needed I can add them.

Thanks to all who helped.

Models - CompanyEmployee being the view model

public class Company
{
    [Key]
    public int id { get; set; }
    [Required]
    public string name { get; set; }
}

public class Employee
{
    [Key]
    public int id { get; set; }
    [Required]
    public string name { get; set; }
    [Required]
    public string jobtitle { get; set; }
    [Required]
    public string number { get; set; }
    [Required]
    public string address { get; set; }
}

public class CompanyEmployee
{
    public Company company { get; set; }
    public List<Employee> employees { get; set; }
}

Index

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

<h2>Index</h2>
<fieldset>
    <legend>Company</legend>
    <table class="table">
        <tr>
            <th>@Html.LabelFor(m => m.company.name)</th>
        </tr>
        <tr>
            <td>@Html.EditorFor(m => m.company.name)</td>
        </tr>
    </table>
</fieldset>
<fieldset>
    <legend>Employees</legend>

        @{Html.RenderPartial("_employeeList", Model.employees);}

</fieldset>
<fieldset>
    @{Html.RenderPartial("_employee", new MMV.Models.Employee());}
</fieldset>
<div class="form-group">
    <div class="col-md-offset-2 col-md-10">
        <input type="submit" value="Submit" class="btn btn-default" />
    </div>
</div>

PartialView of List of Employees

@model IEnumerable<MMV.Models.Employee>
@using (Html.BeginForm("Employees"))
{
    <table class="table">
        <tr>
            <th>
                Name
            </th>
            <th>
                Job Title
            </th>
            <th>
                Number
            </th>
            <th>
                Address
            </th>
            <th></th>
        </tr>
        @foreach (var emp in Model)
        {
            <tr>
                <td>
                    @Html.DisplayFor(modelItem => emp.name)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => emp.jobtitle)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => emp.number)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => emp.address)
                </td>
                <td>
                    <input type="submit" formaction="/Employees/Edit/@emp.id" value="Edit"/>
                    <input type="submit"formaction="/Employees/Delete/@emp.id" value="Remove"/>
                </td>
            </tr>
        }
    </table>
}

Partial View Create Employee

@model MMV.Models.Employee

@using (Html.BeginForm("Create","Employees"))
{
    <table class="table">

        @Html.ValidationSummary(true, "", new { @class = "text-danger" })

        <tr>
            <td>
                @Html.EditorFor(model => model.name)
                @Html.ValidationMessageFor(model => model.name, "", new { @class = "text-danger" })
            </td>
            <td>
                @Html.EditorFor(model => model.jobtitle)
                @Html.ValidationMessageFor(model => model.jobtitle)
            </td>
            <td>
                @Html.EditorFor(model => model.number)
                @Html.ValidationMessageFor(model => model.number, "", new { @class = "text-danger" })
            </td>
            <td>
                @Html.EditorFor(model => model.address)
                @Html.ValidationMessageFor(model => model.address, "", new { @class = "text-danger" })
            </td>
        </tr>
    </table>
    <div class="form-group">
        <div class="col-md-offset-2 col-md-10">
            <input type="submit" value="Create" class="btn btn-default" />
        </div>
    </div>
}

Controller - I used multiple but you can put them all in one

public class CompanyEmployeeController : Controller
{
    private MyContext db = new MyContext();

    // GET: CompanyEmployee
    public ActionResult Index()
    {
        var newCompanyEmployee = new CompanyEmployee();
        newCompanyEmployee.employees = db.EmployeeContext.ToList();
        return View(newCompanyEmployee);
    }

    [HttpPost, ActionName("Delete")]
    public ActionResult DeleteConfirmed(int id)
    {
        Employee employee = db.EmployeeContext.Find(id);
        db.EmployeeContext.Remove(employee);
        db.SaveChanges();
        return RedirectToAction("Index", "CompanyEmployee");
    }

    [HttpPost]
    public ActionResult Create([Bind(Include = "id,name,jobtitle,number,address")] Employee employee)
    {
        if (ModelState.IsValid)
        {
            db.EmployeeContext.Add(employee);
            db.SaveChanges();
            return RedirectToAction("Index", "CompanyEmployee");
        }

        return View(employee);
    }
}

Updated Code - using BeginCollectionItem - dynamic add/delete

Student Partial

@model UsefulCode.Models.Person
<div class="editorRow">
    @using (Html.BeginCollectionItem("students"))
    {
        <div class="ui-grid-c ui-responsive">
            <div class="ui-block-a">
                <span>
                    @Html.TextBoxFor(m => m.firstName)
                </span>
            </div>
            <div class="ui-block-b">
                <span>
                    @Html.TextBoxFor(m => m.lastName)
                </span>
            </div>
            <div class="ui-block-c">
                <span>
                    <span class="dltBtn">
                        <a href="#" class="deleteRow">X</a>
                    </span>
                </span>
            </div>
        </div>
    }
</div>

Teacher Partial

@model UsefulCode.Models.Person
<div class="editorRow">
    @using (Html.BeginCollectionItem("teachers"))
    {
        <div class="ui-grid-c ui-responsive">
            <div class="ui-block-a">
                <span>
                    @Html.TextBoxFor(m => m.firstName)
                </span>
            </div>
            <div class="ui-block-b">
                <span>
                    @Html.TextBoxFor(m => m.lastName)
                </span>
            </div>
            <div class="ui-block-c">
                <span>
                    <span class="dltBtn">
                        <a href="#" class="deleteRow">X</a>
                    </span>
                </span>
            </div>
        </div>
    }
</div>

Register Controller

public ActionResult Index()
{
    var register = new Register
    {
        students = new List<Person>
        {
            new Person { firstName = "", lastName = "" }
        },
        teachers = new List<Person> 
        {
            new Person { lastName = "", firstName = "" }
        }
    };

    return View(register);
}

Register and Person Model

public class Register
{
    public int id { get; set; }
    public List<Person> teachers { get; set; }
    public List<Person> students { get; set; }
}

public class Person
{
    public int id { get; set; }
    public string firstName { get; set; }
    public string lastName { get; set; }
}

Index

@{
    Layout = "~/Views/Shared/_Layout.cshtml";
}
@model UsefulCode.Models.Register
<div id="studentList">
@using (Html.BeginForm())
{
    <div id="editorRowsStudents">
        @foreach (var item in Model.students)
        {
            @Html.Partial("StudentView", item)
        }
    </div>
    @Html.ActionLink("Add", "StudentManager", null, new { id = "addItemStudents", @class = "button" });
}
</div>

<div id="teacherList">
@using (Html.BeginForm())
{
    <div id="editorRowsTeachers">
        @foreach (var item in Model.teachers)
        {
            @Html.Partial("TeacherView", item)
        }
    </div>
    @Html.ActionLink("Add", "TeacherManager", null, new { id = "addItemTeachers", @class = "button" });
}
</div>


@section scripts {
    <script type="text/javascript">
    $(function () {
        $('#addItemStudents').on('click', function () {
            $.ajax({
                url: '@Url.Action("StudentManager")',
                    cache: false,
                    success: function (html) { $("#editorRowsStudents").append(html); }
                });
                return false;
            });
            $('#editorRowsStudents').on('click', '.deleteRow', function () {
                $(this).closest('.editorRow').remove();
            });
            $('#addItemTeachers').on('click', function () {
                $.ajax({
                    url: '@Url.Action("TeacherManager")',
                    cache: false,
                    success: function (html) { $("#editorRowsTeachers").append(html); }
                });
                return false;
            });
            $('#editorRowsTeachers').on('click', '.deleteRow', function () {
                $(this).closest('.editorRow').remove();
            });
        });
    </script>
}

StudentManager Action:

public PartialViewResult StudentManager()
{
    return PartialView(new Person());
}

这篇关于MVC 5 动态行与 BeginCollectionItem的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
C#/.NET最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆