2

IEnumerable<T>私はコレクション(またはIList<T>)を含むモデルを持つASP.NET MVC 4アプリを持っています。

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送信時に、Model Binder はこれをインデックスとプロパティ名の両方に基づいてエンティティのコレクションに変換します。

次に、最後のエディターをコピーし、括弧内のインデックスを 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);
    });

出来上がり!送信すると、もう 1 つの要素が取得されます。

于 2012-08-30T20:37:49.010 に答える
1

最後に、STOが提案していたのと同様のことを行いましたが、Phil Haackによって提案されたコレクションのカスタム(非線形)インデックスを使用しました。

これは要素の手動命名を使用し(したがって、モデルに直接バインドしません)、カスタムインスタンスを使用できます(空の要素テンプレートの場合)。また、インスタンスのコードを生成するためのヘルパーメソッドもいくつか作成したので、モデルまたは空のインスタンスから実際のインスタンスのコードを生成する方が簡単です。

于 2012-09-03T14:46:39.803 に答える
0

ユーザーが#addButtonビューをクリックするたびにテンプレートを挿入するバックボーン(ファイルアップローダー用)の助けを借りてこれを行いました:

@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"));
}

FileUploadInit.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 に答える