64

フォーム内の一連の入力をListMVC 4 の にバインドする場合、次のinput name属性の命名規則が機能することがわかっています。

<input name="[0].Id" type="text" />
<input name="[1].Id" type="text" />
<input name="[2].Id" type="text" />

しかし、モデルバインダーがどれほど寛容であるかに興味があります。たとえば、次の場合はどうでしょう。

<input name="[0].Id" type="text" />
<input name="[3].Id" type="text" />
<input name="[8].Id" type="text" />

モデル バインダーはこれをどのように処理しますか? List長さ 9 の に null をバインドしますか? Listそれとも、長さ 3の にバインドしますか? それとも完全に窒息しますか?

気にする理由

ユーザーがフォームに行を追加したり、フォームから行を削除したりできる動的フォームを実装したいと考えています。したがって、ユーザーが合計 8 行のうち 2 行を削除した場合、後続のすべての入力の番号を付け直す必要があるかどうかを知りたいのです。

4

5 に答える 5

50

コレクションで使用する特定のワイヤ形式があります。これについては、Scott Hanselman のブログで説明されています。

http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx

これについては、Phil Haack の別のブログ エントリで次のように説明されています。

http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx

最後に、ここで必要なことを正確に実行するブログ エントリを示します。

http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/

于 2013-02-12T04:51:56.470 に答える
18

上記のブログにリンクされているこのアプローチに従い、一部の人に役立つ可能性のある詳細をいくつか追加しました。特に、任意の数の行を動的に追加したいが、AJAX を使用して追加したくないためです (フォームを送信するだけにしたかった)。ポストで)。また、連続した ID を維持することについて心配する必要もありませんでした。開始日と終了日のリストを取得していました。

モデルを見る:

public class WhenViewModel : BaseViewModel {
    public List<DateViewModel> Dates { get; set; }
    //... Other properties
}

開始日/終了日表示モデル:

public class DateViewModel {
    public string DateID { get; set; }
    public DateTime? StartDate { get; set; }
    public DateTime? EndDate { get; set; }
}

次に、ページでそれらを使用します(datepickerを使用):

<div class="grid-8-12 clear" id="DatesBlock">
@{
    foreach (DateViewModel d in Model.Dates) {
        @:<div class="grid-5-12 left clear">
            @Html.Hidden("Dates.Index", d.DateID)
            @Html.Hidden("Dates[" + d.DateID + "].DateID", d.DateID) //ID again to populate the view model
            @Html.TextBox("Dates[" + d.DateID + "].StartDate", 
                          d.StartDate.Value.ToString("yyyy-MM-dd"))
        @:</div>
        @:<div class="grid-5-12">
            @Html.TextBox("Dates[" + d.DateID + "].EndDate", 
                          d.EndDate.Value.ToString("yyyy-MM-dd"))
        @:</div>

        <script type="text/javascript">
            $('input[name="Dates[@d.DateID].StartDate"]')
               .datepicker({ dateFormat: 'yy-mm-dd'});
            $('input[name="Dates[@d.DateID].EndDate"]')
               .datepicker({dateFormat: 'yy-mm-dd'});
        </script>
     }
}
</div>
<a href="#" onclick="AddDatesRow()">Add Dates</a>

上記の @ErikTheVikings 投稿にリンクされているブログ投稿で説明されているように、コレクションは@Html.Hidden("Dates.Index", d.DateID)、ページ上のコレクション内の各エントリに対して、非表示要素が繰り返されることによって作成されます。

コレクション内の1つの「行」/アイテムのテンプレートを含む非表示のdivを作成することで、AJAXを使用せずに任意に行を追加してサーバーにデータを送信したかったのです。

非表示の「テンプレート」行:

<div id="RowTemplate" style="display: none">
    <div class="grid-5-12 clear">
        @Html.Hidden("Dates.Index", "REPLACE_ID")
        @Html.Hidden("Dates[REPLACE_ID].DateID", "REPLACE_ID") 
        @Html.TextBox("Dates[REPLACE_ID].StartDate", "")
    </div>
    <div class="grid-5-12">
        @Html.TextBox("Dates[REPLACE_ID].EndDate", "")
    </div>
</div>

次に、テンプレートを複製する jQuery を使用し、新しい行に使用するランダム ID を提供し、現在表示されている複製された行を上記の含まれる div に追加します。

jQuery でプロセスを完了します。

<script type="text/javascript">
    function AddDatesRow() {
        var tempIndex = Math.random().toString(36).substr(2, 5);
        var template = $('#RowTemplate');
        var insertRow = template.clone(false);
        insertRow.find('input').each(function(){ //Run replace on each input
            this.id = this.id.replace('REPLACE_ID', tempIndex);
            this.name = this.name.replace('REPLACE_ID', tempIndex);
            this.value = this.value.replace('REPLACE_ID', tempIndex);
        });
        insertRow.show();
        $('#DatesBlock').append(insertRow.contents());

        //Attach datepicker to new elements
        $('input[name="Dates['+tempIndex+'].StartDate"]')
            .datepicker({dateFormat: 'yy-mm-dd' });
        $('input[name="Dates['+tempIndex+'].EndDate"]')
            .datepicker({dateFormat: 'yy-mm-dd' });
    }
</script>

結果の JSFiddle の例: http://jsfiddle.net/mdares/7JZh4/

于 2014-02-06T16:37:31.820 に答える
3

次のような動的リストがあります。

<ul id="okvedList" class="unstyled span8 editableList">
<li>
    <input data-val="true" data-val-required="The Guid field is required." id="Okveds_0__Guid" name="Okveds[0].Guid" type="hidden" value="2627d99a-1fcd-438e-8109-5705dd0ac7bb">
    --//--
</li>

そのため、行(li要素)を追加または削除すると、アイテムを並べ替える必要があります

    this.reorderItems = function () {
        var li = this.el_list.find('li');

        for (var i = 0; i < li.length; i++) {
            var inputs = $(li[i]).find('input');

            $.each(inputs, function () {
                var input = $(this);

                var name = input.attr('name');
                input.attr('name', name.replace(new RegExp("\\[.*\\]", 'gi'), '[' + i + ']'));

                var id = input.attr('id');
                input.attr('id', id.replace(new RegExp('_.*__', 'i'), '_' + i + '__'));
            });
        }
    };

このリストは、クライアント側から単純な Html.BeginFrom に配置され、サーバー側のアクション パラメータの List と同様に配置されます

于 2013-02-12T04:35:41.970 に答える
1

I also facing similar problem in the past, and I use KnockoutJS to handle such scenario.

Basically, Knockout send the collection in a JSON string, and I deserialized them in my controller.

For more info : http://learn.knockoutjs.com/#/?tutorial=collections

于 2013-02-12T04:43:24.827 に答える