将动态创建的元素绑定到视图中的复杂mvc模型

时间:2013-11-21 10:56:26

标签: c# asp.net-mvc jquery asp.net-mvc-4

我的应用程序中有一个非常庞大的表单,我的模型中有很多不同的输入和很多列表。所以我会尝试添加/删除列表而不将完整的模型发送到服务器。

我现在尝试了几种方法,但我找不到干净的方法。你可以想象我的模型:

public class EditSomething
{
    public string name { get; set;}

    public List<something> somethingList { get; set;}

    // a lot other fields...

    public EditSomething(EditSomethingFromDatabase editSomethingFromDatabase)
    {
        name = editSomethingFromDatabase.Name;
        somethingList = new List<SomethingModel>();
        foreach(var something in editSomethingFromDatabase.Something)  
        {
            somethingList.Add(new SomethingModel(editSomethingFromDatabase.Something));
        }
    }
}

另一个模型看起来很相似但没有列表。

在视图中我有一个模型表:

    <h2>Something</h2> 
    <div id="SomethingDiv">
        <table id="SomethingTable">
            <thead>
                <tr>
                    <th>@Html.Label("SomethingName")</th>
                    <th>@Html.Label("SomethingID")</th>
                                                <th></th>
                </tr>
            </thead>
            <tbody id="SomethingTableBody">

                @Html.EditorFor(x => x.somethingList)

            </tbody>
        </table>
        <p>
            <input type="button" name="addSomething" value="Add Something" id="AddSomething">
        </p>
    </div>

addSomething的jquery是:

  $('#AddSomething').click(function () {
        $.ajax({
            url: '@Url.Action("AddSomething", "SomethingModels")',
            data: { tableSize: $('#SomethingTable tr').length },
            cache: false,
            success: function (html) { $('#SomethingTable tr:last').after(html); }
        });

控制器方法AddSomething是:

public ActionResult AddSomething (int tableSize)
{
    SomethingModel something= new SomethingModel(null, (-2) * (tableSize + 1));
    return PartialView(""~/Views/EditorTemplates/EditSomethingModel.cshtml"", something);
}

至少我在EditorTemplates中有一个编辑器模板和editorfor和partialview。这有我想要发送到服务器的重要信息:

@model SomethingModel
<tr>@TextBoxFor(m=>m.SomethingName)<td>

@TextBoxFor(M =&GT; m.SomethingID)     

现在问题是,第一个视图的提交仅将SomethingModel发布到打开视图时已存在的服务器,但AddMutation方法中的新SomethingModel不在这篇文章。有人想解决这个问题吗?

修改:更改了编辑器模板的路径,因此我只需要EditorForPartialView的一个视图。

Edit2:为解决主要问题,我创建了一个如下视图,并将其用作局部视图。现在数据正确地发送到服务器。只有客户端的验证仍然无效:

@model SomethingModel
    <tr>@TextBoxFor(m=>m.SomethingName, new{Name="somethingList["+ViewBag.ListId+"].SomethingName")<span class="field-validation-valid" data-valmsg-for="somethingList[@ViewBag.ListId].SomethingName" data-valmsg-replace="true"></span><td>
<tr>@TextBoxFor(m=>m.SomethingID, new{Name="somethingList["+ViewBag.ListId+"].SomethingID")<span class="field-validation-valid" data-valmsg-for="somethingList[@ViewBag.ListId].SomethingID" data-valmsg-replace="true"></span><td>
</tr>

AddSomething方法中,我添加了ViewBag.ListId,其中包含列表中下一个元素的ID。

1 个答案:

答案 0 :(得分:2)

这似乎是一个合理的方法,但你没有展示你的EditorTemplate,所以我将假设它的东西:

@model List<something>

@for(int i = 0; i < Model.Count; i++)
{
   <tr>
     <td>@Html.DisplayFor(m => m[i].Id) @Html.HiddenFor(m => m[i].Id)</td>
     <td>@Html.EditorFor(m => m[i].Name)</td>
   </tr>
}

你的ajax方法应该返回一行的HTML - 这很重要......表单字段需要在表格的最后一个上面命名为1。

因此,当您查看表的渲染源时(在添加任何新字段之前,它可能看起来像:

...
<tbody>
   <tr>
     <td>1 <input type="hidden" name="something[0].Id" value="1"/></td>
     <td><input type="text" name="something[0].Name" value="somename" /></td>
   </tr>
</tbody>

您需要确保新行的ajax方法返回的html为:

   <tr>
     <td>2 <input type="hidden" name="something[1].Id" value="2"/></td>
     <td><input type="text" name="something[1].Name" value="somenewname" /></td>
   </tr>

即。括号内的数字是某个项目中的下一个索引。如果索引中存在间隙(或它们重叠),则不会解析新项目。

编辑 - 要使客户端验证适用于新字段,请更改jquery ajax成功回调,如下所示:

$('#AddSomething').click(function () {
    $.ajax({
        url: '@Url.Action("AddSomething", "SomethingModels")',
        data: { tableSize: $('#SomethingTable tr').length },
        cache: false,
        success: function (html) { 
            $('#SomethingTable tr:last').after(html);
            $.validator.unobtrusive.parse('#SomethingTable');
        }
    });