例えば似たようなSelectBoxを大量に配置したい場合

入力フォームいっぱいある中で、セレクトボックスを大量に配置する。
DBにSelectBoxで入力させたい情報を持っててその数が動的に増減するとか。

public class SampleViewModel{  
    public string text1 {get; set;}  
    public string text2 {get; set;}  
    public string text3 {get; set;}  
    public List<SelectViewModel> selects {get; set;}  
}  

public class SelectViewModel{  
    public string labelName {get; set;}  
    public string labelId {get; set;}  
    public string selectVal {get; set;}  

    public List<SelectListItem> selectList {get; set;}  
}

SelectViewModelをDBデータの数だけnewして、ラベル名とか選択肢ぶちこんで、親のViewModelのselectsにひたすらAddする。

以下はダメパターン。

@model SampleViewModel  
<form asp-controller="" asp-action="" methods="post">  
    <input asp-for="text1">  
    <input asp-for="text2">  
    <input asp-for="text3">  
    @foreach(var select in Model.selects)  
    {  
        <label for="@select.labelName" id="@select.labelId">@select.labelName</label>  
        <select asp-for="selectVal" asp-items="@select.selectList">  
    }  
    <button type="submit">  
</form>

表示自体はうまくいくものの、ユーザーの選択が正常にPostされない(モデルバインド失敗)

foreachを使わず、forで回し、SelectViewModel毎に連番が付いたname属性を付与する。
また、SelectはHtmlタグヘルパーで出力する。

@model SampleViewModel  
<form asp-controller="" asp-action="" methods="post">  
    <input asp-for="text1">  
    <input asp-for="text2">  
    <input asp-for="text3">  
    @for(var i = 0; i < Model.selects.Count(); i++)  
    {  
        <label for="@Model.selects[i].labelName" id="@select.labelId" name="sel[@i].labelId">@Model.selects[i].labelName</label>  

        <input type="hidden" name="selects[@i].labelId" value="@Model.Model.selects[i].labelId">  

        @Html.DropDownListFor(model => model.selects[i].selectVal),  
        (Model.selects[i].selectList),  
        new { @id = "selectList[i]"}  
    }  
    <button type="submit">  
</form>

本来、LabelもHtmlタグヘルパーで出力してモデルバインドできるが、配列を回す場合のみ、DropDownListForと同じ書き方をしてもname属性で配列の[]が正常にエスケープされず、モデルバインドできない。
仕方ないので、LabelIdはhiddenに値を埋め込んでバインドさせた。
HiddenタグもHtmlタグヘルパーがあるけど書き方調べるの面倒なので省略。

Modelに埋め込んだModelにバインドさせるなら部分ビューを使いたかったが、ネット上にある例はすべて単体のModelを部分ビューに渡してバインドする例ばかりで、ListのModelを渡してバインドする方法は見当たらず、試してみたができなかった。
(ListのModelを部分ビューに渡してデータを描画するだけならできるが、モデルバインドができない)
今後の課題。

参考

ASP.NET MVC ViewからControllerへModelのListを渡す方法
How to override the “name” HtmlAttribute of Razor
選択ボックス/リストボックスを生成する - DropDownListFor/ListBoxForメソッド[Razor]
Model Binding To List Of Objects In ASP.NET MVC
MVC5でビューモデルを部分ビューで更新するにはどうすればよいですか?
ASP.NET MVC - 部分ビューにあるinput要素のname属性にプレフィックスを付ける
ASP.NET MVC ラジオボタンのView/Controllerのやり取り
ASP.NET MVCの用語

関連記事

この記事へのコメント

まだコメントはありません
1
@np8ZkmJc63pMcc09の技術ブログ
1
このエントリーをはてなブックマークに追加