我的MVC应用程序具有经典的父子关系(master-detail)。
我希望有一个页面可以在同一页面上创建新的父级和子级。我添加了一个动作,它返回一个局部视图,并将子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)创建新的FormField(子)。
@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());
}
提前致谢,
沙龙。
答案 0 :(得分:1)
我认为最好和最简单的方法是,您可以创建Form
视图,并在其底部放置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>
通过在创建场所视图中调用此局部视图ajaxly,您可以为每个标记渲染一些元素。每行元素都包含一个标签,一个包含标签的DropDownList,以及一个删除按钮,只需删除创建的元素。
在创建位置视图中,您有一个裸表,其中包含您通过局部视图创建的元素:
<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调用和模型绑定。我试图向你展示道路,因为我真的不能在这个答案中发布所有这些内容。
Here是完整信息和操作方法。
希望这个答案有用并引导您。
答案 1 :(得分:1)
您可以在父cshtml页面中使用@ Html.RenderPartial(_CreateFormField.cshtml)htlper方法。
对于模式信息,http://msdn.microsoft.com/en-us/library/dd492962(v=vs.118).aspx
我提供了一个伪代码示例
@Foreach(childModel in model.FormFields)
{
@Html.RenderPartial("childView.cshtml","Name", childModel)
}
请以正确的c#语法方式尝试,您将获得为每个集合项呈现的部分视图。
答案 2 :(得分:0)
问题是您的部分视图需要使用:
@model Form //Instead of FormField
然后在局部视图内部,您必须使用model =&gt;模型。的 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。这样编辑器可以独立于Parent,并且您可以在任何页面上添加 Form ,而不仅仅是您还要添加FormField的页面。
然后你会替换
@Html.Partial("view")
带
@Html.EditorFor()
基本上,我发现在编辑时使用@ Html.EditorFor而不是部分视图要好得多(它被称为视图 - 而不是编辑器)。
答案 3 :(得分:0)
如果您想使用基于网格的布局,可以尝试Kendo UI grid
答案 4 :(得分:0)
使用jQuery在点击按钮时添加FormField。
类似我使用它如下
<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>
希望这对你有帮助。