在同一页上创建新的父级和子级。

13

我的MVC应用程序有一个经典的父子关系(主细节)。

我想要创建一个单独的页面,在同一页上创建新的父级和子级。我已经添加了一个动作,返回一个局部视图,并将子HTML添加到父视图中,但我不知道如何将动作中新创建的子项与原始父项相关联(换句话说,如何将新的子实体添加到父实体的这些实体集合中)。

我猜测,当我提交表单时,操作应该获取具有其集合中新创建的子项的父实体。

简而言之,应该是创建子实体的动作代码是什么,子实体如何添加到其父实体集合中?

我在这里阅读了很多帖子(和其他网站),但没有找到示例。

应用程序使用MVC 4和Entity Framework 5。

代码示例(我删除了一些代码以使其简单化)。模型是Form(父项)和FormField(子项)实体。

public partial class Form
{ 
    public int ID { get; set; }
    public string Name { get; set; }

    public virtual ICollection<FormField> FormFields { get; set; }
}

public partial class FormField
{
    public int ID { get; set; }
    public string Name { get; set; }
    public int FormID { get; set; }
}
以下部分视图 (_CreateFormField.cshtml) 创建新的表单字段(子级)。
@model FormField

@using (Html.BeginForm()) {
@Html.ValidationSummary(true)

<fieldset>
    <legend>FormField</legend>

    <div class="editor-label">
        @Html.LabelFor(model => model.Name)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.Name)
        @Html.ValidationMessageFor(model => model.Name)
    </div>

    <div class="editor-label">
        @Html.LabelFor(model => model.FormID)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.FormID)
        @Html.ValidationMessageFor(model => model.FormID)
    </div>


</fieldset>
}

以下视图(Create.cshtml)是创建表单的视图。

@model Form

@using (Html.BeginForm()) {
@Html.ValidationSummary(true)

<fieldset>
    <legend>Form</legend>

    <div class="editor-label">
        @Html.LabelFor(model => model.Name)
    </div>
    <div class="editor-field">
        @Html.EditorFor(model => model.Name)
        @Html.ValidationMessageFor(model => model.Name)
    </div>

<div>
        @Html.ActionLink(
                "Add Field",
                "CreateFormField", 
                new { id = -1},
                new { @class = "form-field" })
    </div>
    <p>
        <input type="submit" value="Create" />
    </p>
</fieldset>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

<div id="CreateFormField"></div>

@section Scripts {
<script>
    $(function () {
        $('.form-field').on('click', function (e) {

            $.get($(this).prop('href'), function (response) {
                $('#CreateFormField').append(response)
            });

            e.preventDefault();
        });
    });
</script>

@Scripts.Render("~/bundles/jqueryval")

}
以下操作处理FormController中的创建。
[HttpPost]
public ActionResult Create(Form form)
{
    if (ModelState.IsValid)
    {
        db.Forms.Add(form);
        db.SaveChanges();
        return RedirectToAction("Index");
    }

    return View(form);
}

public ActionResult CreateFormField(string id = null)
{
    // I guess something is missing here.

    return PartialView("_CreateFormField", new FormField());
}

提前致谢,

沙龙。


3
你能展示目前为止你写的代码吗?当配有具体的代码示例时,解释会更好理解。 - Darin Dimitrov
我注意到的一个问题是,这个局部视图包含一个表单。我已经将其删除,但它并没有改变问题。 - Sharon Eden
1
有人吗?这应该是一个非常普遍的情况。 - Sharon Eden
http://www.progware.org/Blog/post/ASPNET-MVC-Binding-to-Listse28093Enumerables-on-POST-with-JQuery.aspx - softawareblog.com
5个回答

1
我认为对你来说最好、最简单的方法是创建一个视图来创建表单,然后在底部放置一个 fieldset 来分配 FormFields。
对于 fieldset,你应该有两个部分视图:一个用于创建,另一个用于编辑。创建的部分视图应该像这样:
@model myPrj.Models.Form_FormFieldInfo

@{ 
    var index = Guid.NewGuid().ToString(); 
    string ln = (string)ViewBag.ListName;
    string hn = ln + ".Index";
}

<tr>
    <td>        
        <input type="hidden" name="@hn" value="@index" />
        @Html.LabelFor(model => model.FormFieldID)
    </td>
    <td>
        @Html.DropDownList(ln + "[" + index + "].FormFieldID", 
            new SelectList(new myPrj.Models.DbContext().FormFields, "ID", "FieldName"))
    </td>        
    <td>
        <input type="button" onclick="$(this).parent().parent().remove();" 
            value="Remove" />
    </td>
</tr>

通过在创建地点视图中以Ajax方式调用此部分视图,您可以为每个标签呈现一些元素。每行元素都包含一个标签、一个包含标签的下拉列表和一个删除按钮,以便简单地删除已创建的元素。
在创建地点视图中,您有一个空表格,其中将包含通过部分视图创建的这些元素:
<fieldset>
     <legend>Form and FormFields</legend>
     @Html.ValidationMessageFor(model => model.FormFields)</label>
     <table id="tblFields"></table>                                        
     <input type="button" id="btnAddTag" value="Add new Field"/>
     <img id="imgSpinnerl" src="~/Images/indicator-blue.gif" style="display:none;" />
</fieldset>

而你有以下脚本来为每个标签创建一个元素行:

$(document).ready(function () {
    $("#btnAddField").click(function () {
        $.ajax({
            url: "/Controller/GetFormFieldRow/FormFields",
            type: 'GET', dataType: 'json',
            success: function (data, textStatus, jqXHR) {
                $("#tblFields").append(jqXHR.responseText);
            },
            error: function (jqXHR, textStatus, errorThrown) {
                $("#tblFields").append(jqXHR.responseText);
            },
            beforeSend: function () { $("#imgSpinnerl").show(); },
            complete: function () { $("#imgSpinnerl").hide(); }
        });
    });
});

GetFormFieldRow 方法如下:

public PartialViewResult GetFormFieldRow(string id = "")
    {            
        ViewBag.ListName = id;
        return PartialView("_FormFieldPartial");
    }

你只需要完成创建...你的问题的整个解决方案包含了许多关于视图、局部视图、控制器、ajax调用和模型绑定的代码。我尝试向你展示方法,因为我无法在此答案中全部贴出它们。

这里是完整信息和操作步骤。

希望这个回答对你有用,并为你指明方向。


1

您可以在父cshtml页面中使用@Html.RenderPartial(_CreateFormField.cshtml)帮助程序方法。

有关更多信息,请参见http://msdn.microsoft.com/en-us/library/dd492962(v=vs.118).aspx

我提供了一个伪代码示例,

@Foreach(childModel in model.FormFields)
{
    @Html.RenderPartial("childView.cshtml","Name", childModel)
}

请以适当的C#语法方式尝试,您将为每个集合项呈现部分视图。

0

使用jQuery,在单击按钮时添加表单字段。

类似的,我已经按照如下方式使用它

 <div class="accomp-multi-field-wrapper">
 <table class="table">
    <thead>
        <tr>
            <th>Name</th>
            <th>FormId</th>
            <th>Remove</th>
           </tr>
     </thead>
<tbody class="accomp-multi-fields">
 <tr class="multi-field">
        <td> <input name="FormFields[0].Name" type="text" value=""></td>
        <td> <input name="FormFields[0].FormId" type="text" value=""></td>
        <td> <button type="button" class="remove-field">X</button></td>
     </tr> 

</tbody>
<tr>
    <th><button type="button" class="add-field btn btn-xs btn-primary addclr"><i class="fa fa-plus"></i> Add field</button> </th>
</tr>
</table>
</div>

添加和删除字段的jQuery代码如下:

 <script>
 $('.accomp-multi-field-wrapper').each(function () {
          var $wrapper = $('.accomp-multi-fields', this);
          $(".add-field", $(this)).click(function (e) {
          var $len = $('.multi-field', $wrapper).length;
          $('.multi-field:first-child', $wrapper).clone(false, true).appendTo($wrapper).find('select,input,span').val('').each(function () {
          $(this).attr('name', $(this).attr('name').replace('\[0\]', '\[' + $len + '\]'));
    });

$(document).on("click",'.multi-field .remove-field', function () {
            if ($('.multi-field', $wrapper).length > 1) {
                $(this).closest('tr').remove();
                //
                $('.multi-field', $wrapper).each(function (indx) {
                    $(this).find('input,select,span').each(function () {
                      $(this).attr('name', $(this).attr('name').replace(/\d+/g, indx));

                    })
                })
            }
        });
    </script>

希望这能对你有所帮助。

0

问题在于您的部分视图需要使用:

@model Form //Instead of FormField

然后在部分视图中,您必须使用 model => model.FormField.x。

<div class="editor-label">
    @Html.LabelFor(model => model.FormField.Name)
</div>
<div class="editor-field">
    @Html.EditorFor(model => model.FormField.Name)
    @Html.ValidationMessageFor(model => model.FormField.Name)
</div>

这仅适用于一对一的关系(或者我在这个帖子中读到的是这样:Here)。如果您在局部视图中有@Html.Form,也没有关系。

在进行这些更改后,我没有任何问题将所有发布的数据发送回控制器。

编辑:我遇到了问题,正如任何人很快就会发现的那样。

更好的方法(我见过的)是使用EditorTemplate。这样,编辑器保持独立于父级,并且您可以在任何页面上添加表单,而不仅仅是在您还要添加FormField的页面上。

然后您将替换

@Html.Partial("view")

使用

@Html.EditorFor()

基本上,我发现在进行编辑时使用@Html.EditorFor比使用部分视图要好得多(它被称为视图-而不是编辑器)。

0

如果您想使用基于网格的布局,可以尝试使用Kendo UI grid


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接