MVC Razor创建要提交的对象列表

Sof*_*Eng 8 c# asp.net-mvc-5

我是一位经验丰富的.NET C#软件开发人员,但仅在几个月前我开始使用MVC Razor(MVC 5).

我有一个小情况,我在网上找不到任何答案(搜索后数小时)

我有一个模型,其中包含另一个模型的列表,该模型又具有如下所示的模型列表.

public class Parent
{
    public string Name { get; set; }
    public string Sex { get; set; }
    public int Age { get; set; }
    public List<Child> Children { get; set; } 
}

public class Child
{
    public string Name { get; set; }
    public string Sex { get; set; }
    public int Age { get; set; }
    public List<GrandChild> GrandChildren { get; set; } 
}

public class GrandChild
{
    public string Name { get; set; }
    public string Sex { get; set; }
    public int Age { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我的控制器有2个方法,一个是主要的Get,另一个是post,以便发布新数据

public ActionResult Index()
{
    return View();
}

[HttpPost]
public ActionResult PostParent(Parent parent)
{
    if (ModelState.IsValid)
    {
        //Do an insert to the DB
        return View("~/Views/Home/Index.cshtml");
    }

    return Json("Error");
}
Run Code Online (Sandbox Code Playgroud)

但是在我的表单视图中,我找不到创建添加按钮并将新数据插入Children和GrandChildren列表的方法(包括孩子)

@using (Html.BeginForm("PostParent", "Home", FormMethod.Post, new {@class = "form-horizontal", role = "form"}))
{
    @Html.LabelFor(x => x.Name)
    @Html.TextBoxFor(x => x.Name)
}
Run Code Online (Sandbox Code Playgroud)

我只能添加原始类型的字段,但不能添加对象.

我真的很感激任何帮助!

Daw*_*wan 12

为此,您可以使用Html.BeginCollectionItem https://www.nuget.org/packages/BeginCollectionItem/

你可以做的是有一个主表格的视图并将Parent模型传递给它,因为这将代表父,那么你将需要一行代表一个孩子,你可以称之为ChildRow.cshtml

因此,对于Parent,我们正在创建Create.cshtmlView,我们将传递Parent Model.

@model Parent

@using(Html.BeginForm())
{
   @Html.TextBoxFor(m => m.Name)


    <table id="children">
        <tbody>

<!-- This here will display the Child Row for existing Rows in the Parent model -->

            @foreach (var child in Model.Children )
            {
                @Html.Partial("ChildRow", child)
            }
        </tbody>

    </table>
<button  type="button" id="addChild">Add Child</button>

<button type="submit"> Save</button>
    }
Run Code Online (Sandbox Code Playgroud)

那么这就是ChildRow.cshtml的样子,它将有一个Child模型.

注意:您必须将IsDeleted属性添加到子模型,这将帮助您在控制器中 - 查看Child是否被删除.

@model Child

@using (Html.BeginCollectionItem("Children"))
{
    <tr>
        <td>
             @Html.HiddenFor(m => m.IsDeleted, new { data_is_deleted = "false" })
            @Html.HiddenFor(m => m.ChildId)
            @Html.TextBoxFor(m => m.Name )
        </td>

        <td>
             <span class="glyphicon glyphicon-trash action-icon" data-action="removeItem"></span>
        </td>


    <tr>
}
Run Code Online (Sandbox Code Playgroud)

现在,当Add Child单击按钮时,您必须在表的末尾添加一行.

为此,您将在Controller中创建一个新操作:

    public ActionResult AddChild()
    {
        return PartialView("Child", new Child());
    }
Run Code Online (Sandbox Code Playgroud)

然后将此jQuery添加到 Create.cshtml

    $("#addChild").on("click", function () {
        $.ajax({
            url: '@Url.Action("AddChild", "YourController")'
        }).success(function (partialView) {
            $('#children> tbody:last-child').append(partialView);
        });
    });
Run Code Online (Sandbox Code Playgroud)

这将在表中附加一个新的子行

如果你想在同一页面上删除,你也必须隐藏/禁用该行,因为你可以添加这个jQuery:

$('body').on("click", '*[data-action="removeItem"]', function (e) {
    e.stopPropagation();
    var btn = $(this);
    var row = btn.closest('tr');
    var firstCell = $(row.find('td')[0]);
    var checkBox = firstCell.find('*[data-is-deleted]');
    var checkBoxVal = checkBox.val();

    if (checkBoxVal === 'False' || checkBox.val() === 'false') {
        checkBox.val('true');
        row.find('td').find('input, textarea, select').attr('readonly', 'readonly');
    } else {
        checkBox.val('false');
        row.find('td').find('input, textarea, select').attr("readonly", false);
    }

});
Run Code Online (Sandbox Code Playgroud)

然后当您回到控制器时,您将看到模型中的子列表.

[HttpPost]
public ActionResult Create(Parent model)
{

   var newChildren = model.Children.Where(s => !s.IsDeleted && s.ChildId == 0);

   var updated = model.Children.Where(s => !s.IsDeleted && s.ChildId != 0);

   var deletedChildren = model.Children.Where(s => s.IsDeleted && s.ChildId != 0);


    return View(model);
}
Run Code Online (Sandbox Code Playgroud)

你将不得不为GrandChildren做类似的事情.


H. *_*aya 2

<input/>我认为你需要一个你应该从 HTML5 中了解的常用标准。如果我理解正确的话,您想将数据从视图传递到控制器。现在您应该需要在您创建的表单中添加一个按钮。您需要/应该通过将模型数据从视图传递到控制器来调用控制器。@Html.ActionLink()是一个剃刀助手<Input>

表单中类似这样的东西可能应该可以解决问题:

@Html.ActionLink("Click here to pass", "ActionName", new { ParameterNameOfTheController = Model })
Run Code Online (Sandbox Code Playgroud)

这些东西背后的逻辑应该发生在控制器中。我希望这可以帮助你。