2

我有一个带有模型的 ASP.NET MVC 4 应用程序,其中包含和集合(IEnumerable<T>IList<T>),即:

class MyModel
{
  public int Foo { get; set; }
  public IList<Item> Bar { get; set; }
}

class Item
{
  public string Baz { get; set; }
}

我用经典@for...@Html.EditorFor...广告等方式渲染视图中的数据。现在需要在客户端添加动态添加新项目,然后将其发布回服务器。

我正在寻找一种简单的解决方案来处理添加(在 JavaScript 中),也就是不手动创建所有输入等。可能以某种方式从编辑器模板视图中获取它。并添加它,当表单提交回服务器时,模型绑定器将能够正确创建IList<T>集合,也就是对输入名称的一些智能处理。我读了一堆文章,但没有什么是简单且可靠的(没有像集合变量名称这样的魔术字符串,对服务器的 AJAX 回调......)。

到目前为止,看起来很有希望,但我宁愿依靠服务器上的渲染(预先知道的项目)。

4

3 回答 3

4

我不确定你是什么意思'集合变量名',可能我的解决方案是你注意到的一种魔法。

我的解决方案是基于复制元素的现有编辑器并通过 Javascript 更改输入名称。

首先,我们需要标记我们的编辑器。这是用于收集的表单输出编辑器的代码

        @for (var i = 0; i < Model.Count; i++)
        {
            <div class="contact-card">
                @Html.LabelFor(c => Model[i].FirstName, "First Name")
                @Html.TextBoxFor(c => Model[i].FirstName)
                <br />
                @Html.LabelFor(c => Model[i].LastName, "Last Name")
                @Html.TextBoxFor(c => Model[i].LastName)
                <br />
                @Html.LabelFor(c => Model[i].Email, "Email")
                @Html.TextBoxFor(c => Model[i].Email)
                <br />
                @Html.LabelFor(c => Model[i].Phone, "Phone")
                @Html.TextBoxFor(c => Model[i].Phone)
                <hr />
            </div>

        }

我们的编辑器被放入带有 class 的 div 中contact-card。在呈现时,ASP.NET MVC 为用作属性编辑器的输入提供类似[0].FirstName, [0].LastName...[22].FirstName的名称。[22].LastName在提交模型绑定器将其转换为基于索引和属性名称的实体集合。

接下来我们创建复制最后一个编辑器并将括号中的索引增加 1 的 javascript 函数。在提交时将附加元素添加到集合中:

var lastContent = $("#contact-form .contact-card").last().clone();
$("#contact-form .contact-card").last().after(lastContent);

$("#contact-form .contact-card")
    .last()
    .find("input")
    .each(function () {
        var currentName = $(this).attr("name");
        var regex = /\[([0-9])\]/;
        var newName = currentName.replace(regex, '[' + (parseInt(currentName.match(regex)[1]) + 1) + ']');
        $(this).val('');
        $(this).attr('name', newName);
    });

瞧!!提交后,我们将获得更多元素!

于 2012-08-30T20:37:49.010 回答
1

最后,我按照STO 的建议做了类似的事情,但使用了Phil Haack 建议的集合的自定义(非线性)索引。

这使用了元素的手动命名(因此我没有直接绑定到模型)并且我可以使用自定义实例(对于空元素模板)。我还创建了一些辅助方法来为实例生成代码,因此从模型或空实例生成实际实例的代码更容易。

于 2012-09-03T14:46:39.803 回答
0

我在 Backbone(用于文件上传器)的帮助下做到了这一点,每当用户单击 #addButton View 时,我都会在其中插入模板:

@using Telerik.Web.Mvc.UI
@{
    ViewBag.Title = "FileUpload";
    Layout = "~/Areas/Administration/Views/Shared/_AdminLayout.cshtml";
}
<div id="fileViewContainer" class="span12">
<h2>File upload</h2>
@foreach(var fol in (List<string>)ViewBag.Folders){
        <span style="cursor: pointer;" class="uploadPath">@fol</span><br/>
    }
    @using (Html.BeginForm("FileUpload", "CentralAdmin", new { id = "FileUpload" }, FormMethod.Post, new { enctype = "multipart/form-data" }))
    {
        <label for="file1">Path:</label>
        <input type="text" style="width:400px;" name="destinacionPath" id="destinacionPath"/><br />
        <div id="fileUploadContainer">
            <input type="button" class="addButton" id="addUpload" value="Add file"/>
            <input type="button" class="removeButton" id="removeUpload" value="Remove file"/>
        </div>

        <input type="submit" value="Upload" />
    }
</div>
<script type="text/template" id="uploadTMP">
     <p class="uploadp"><label for="file1">Filename:</label>
     <input type="file" name="files" id="files"/></p>
</script>
@{
    Html.Telerik().ScriptRegistrar().Scripts(c => c.Add("FileUploadInit.js"));
}

文件上传初始化.js

$(document).ready(function () {
    var appInit = new AppInit;
    Backbone.history.start();
});
window.FileUploadView = Backbone.View.extend({
    initialize: function () {
        _.bindAll(this, 'render', 'addUpload', 'removeUpload', 'selectPath');
        this.render();
    },
    render: function () {
        var tmp = _.template($("#uploadTMP").html(), {});
        $('#fileUploadContainer').prepend(tmp);
        return this;
    },
    events: {
        'click .addButton': 'addUpload',
        'click .removeButton': 'removeUpload',
        'click .uploadPath': 'selectPath'
    },
    addUpload: function (event) {
        this.render();
    },
    removeUpload: function (event) {
        $($('.uploadp')[0]).remove();
    },
    selectPath: function (event) {
        $('#destinacionPath').val($(event.target).html());
    }
});
var AppInit = Backbone.Router.extend({
    routes: {
        "": "defaultRoute"
    },
    defaultRoute: function (actions) {
        var fileView = new FileUploadView({ el: $("#fileViewContainer") });
    }
});

在控制器中,您保留您的代码

我希望这将有所帮助。

于 2012-08-30T19:29:27.277 回答