几天来我一直在努力解决这个问题,但无法弄清楚。我需要创建一个视图,允许用户添加和删除复杂的分层对象。假的例子:
楷模
public class ParentModel
{
public int ParentId { get; set; }
public string ParentText { get; set; }
public IList<ChildModel> Children { get; set; }
}
public class ChildModel
{
public int ChildId { get; set; }
public string ChildText { get; set; }
public IList<GrandChildModel> GrandChildren { get; set; }
}
public class GrandChildModel
{
public int GrandChildId { get; set; }
public string GrandChildText { get; set; }
}
现在,假设我有一个填充 aParentModel
及其子属性的操作,一个简单的视图可能如下所示:
@model EditorTemplateCollectiosns.Models.ParentModel
@using (@Html.BeginForm())
{
<div>
@Html.TextBoxFor(m => m.ParentId)
@Html.TextBoxFor(m => m.ParentText)<br/>
Children:<br/>
@for (var i = 0; i < Model.Children.Count; i++)
{
@Html.TextBoxFor(m => Model.Children[i].ChildId)
@Html.TextBoxFor(m => Model.Children[i].ChildText)
<div>
Grandchildren:<br/>
<table id="grandChildren">
<tbody>
@for (var j = 0; j < Model.Children[i].GrandChildren.Count; j++)
{
<tr>
<td>@Html.TextBoxFor(m => @Model.Children[i].GrandChildren[j].GrandChildId)</td>
<td>@Html.TextBoxFor(m => @Model.Children[i].GrandChildren[j].GrandChildText)</td>
</tr>
}
</tbody>
</table>
</div>
}
</div>
<button type="button" id="addGrandchild">Add Grandchild</button>
<input type="submit" value="submit"/>
}
<script type="text/javascript">
$(document).ready(function() {
$("#addGrandchild").click(function() {
$("#grandChildren tbody:last").append('<tr><td><input type="text" name="grandChildId" /></td><td><input type="text" name="grandChildText" /></td></tr>');
});
});
</script>
除非我添加孙子并提交表单,否则此视图工作正常,在这种情况下,它不会绑定到GrandChildModel
. POST的小提琴:
所以我尝试使用编辑器模板GrandChildModel
,看看它是否可以工作。这很适合简单地显示对象,但我不知道如何将孙子添加到列表中并将其显示在编辑器模板中。我还尝试嵌套加载$.ajax
调用的局部视图,但这变成了后勤方面的噩梦。
在实际应用中,层次结构比这个例子更深,每个后续的子对象都需要有这个添加/删除能力。每次用户想要添加或删除对象时,如果没有完整的表单帖子,这是否可能?使用上面示例中的方法,是否可以让新添加的孙子绑定到IList
on POST?或者,有没有一种方法可以在客户端添加一个对象并将其显示在编辑器模板中并绑定到IList
on POST?如果这两种选择都不是正确的方法,那是什么?
更新
我已经想出了一些可能有用的hacky,但我仍然很想知道是否有更简单的方法来做到这一点。我将上面的视图代码更改为:
@model EditorTemplateCollectiosns.Models.ParentModel
@using (@Html.BeginForm())
{
<div>
@Html.TextBoxFor(m => m.ParentId)
@Html.TextBoxFor(m => m.ParentText)<br/>
Children:<br/>
<button type="button" id="addChild" onclick="addChildRow()">Add Child</button>
<table id="children">
<tbody class="childTableBody">
@for (var i = 0; i < Model.Children.Count; i++)
{
<tr>
<td colspan="3">Child @i</td>
</tr>
<tr class="childInfoRow">
<td>
@Html.TextBoxFor(m => Model.Children[i].ChildId)
</td>
<td>
@Html.TextBoxFor(m => Model.Children[i].ChildText)
</td>
<td>
<button type="button" id="removeChild@(i)" onclick="removeChildRow(this)">Delete</button>
</td>
</tr>
<tr>
<td colspan="3">
Grandchildren:<br/>
<button type="button" id="addGrandchild@(i)" onclick="addGrandchildRow(this)">Add Grandchild</button>
<table id="grandChildren@(i)">
<tbody>
@for (var j = 0; j < Model.Children[i].GrandChildren.Count; j++)
{
<tr>
<td>@Html.TextBoxFor(m => @Model.Children[i].GrandChildren[j].GrandChildId)</td>
<td>@Html.TextBoxFor(m => @Model.Children[i].GrandChildren[j].GrandChildText)</td>
<td><button type="button" id="removeGrandchild@(i)_@(j)" onclick="removeGrandchildRow(this)">Delete</button></td>
</tr>
}
</tbody>
</table>
</td>
</tr>
}
</tbody>
</table>
</div>
<input type="submit" value="submit"/>
}
然后,我添加了以下 javascript。在每次添加/删除似乎无法正常工作后,我无法使用类和 jQuery click 事件处理程序作为重新绑定处理程序:
<script type="text/javascript">
function addChildRow() {
var newRowIndex = $("#children tr.childInfoRow").length;
var newRow = '<tr><td colspan="3">Child ' + newRowIndex + '</td></tr><tr class="childInfoRow"><td><input type="text" name="Children[' + newRowIndex + '].ChildId" /></td>' +
'<td><input type="text" name="Children[' + newRowIndex + '].ChildText" /></td>' +
'<td><button type="button" id="removeChild' + newRowIndex + '" onclick="removeChildRow(this)">Delete</button></td></tr>' +
'<td colspan="3">Grandchildren: <br/><button type="button" id="addGrandchild' + newRowIndex + '" onclick="addGrandchildRow(this)">Add Grandchild</button>' +
'<table id="grandChildren' + newRowIndex + '"><tbody></tbody></table></td></tr>';
$("#children tbody.childTableBody:last").append(newRow);
}
function addGrandchildRow(elem) {
var childIndex = $(elem).attr('id').replace('addGrandchild', '');
var newRowIndex = $("#grandChildren" + childIndex + " tr").length;
var newRow = '<tr><td><input type="text" name="Children[' + childIndex + '].GrandChildren[' + newRowIndex + '].GrandChildId" /></td>' +
'<td><input type="text" name="Children[' + childIndex + '].GrandChildren[' + newRowIndex + '].GrandChildText" /></td>' +
'<td><button type="button" id="removeGrandchild' + childIndex + '_' + newRowIndex + '" onclick="removeGrandchildRow(this)">Delete</button></td></tr>';
$("#grandChildren" + childIndex + " tbody:last").append(newRow);
}
function removeChildRow(elem) {
$(elem).closest('tr').prev().remove();
$(elem).closest('tr').next().remove();
$(elem).closest('tr').remove();
}
function removeGrandchildRow(elem) {
$(elem).closest('tr').remove();
}
</script>
到目前为止,这是有效的,并且数组值似乎正确绑定。但是,我不喜欢在任一表中添加一行所需的大量内容。有没有人有更好的主意?