shuhelohelo’s blog

Xamarin.Forms多めです.

ASP.NET Coreでチェックボックスリストの作り方。チェックされた項目の取得方法

youtu.be

画像中段のようなチェックボックスのリストを使う機会が多い.

f:id:shuhelohelo:20191118215225p:plain

選択状態を表示させ,ユーザーによる選択の状態をサーバー側に送ったりする.

例えば,以下のようなViewModelを使うとする.

このViewModelはItemsというリストを持っていて,そのリストの要素Itemは選択状態を保持するIsSelectedプロパティを持っている.

とする.

このアイテムのチェックボックスリストを表示し,ユーザーに選択させてそれをサーバー側で受け取り,DBなどに保存する.

ということがよくある.

    //ViewModel
    public class PersonViewModel
    {
        public string Name { get; set; }
        public decimal Age { get; set; }

        public IList<Item> Items { get; set; }
    }

    //Itemモデル
    public class Item
    {
        public string Name { get; set; }
        public decimal Price { get; set; }
        public bool IsSelected { get; set; }
    }

これをView側で以下のように表示させる.

@model CheckboxPractice.ViewModels.PersonViewModel

<form method="post" action="checkboxlist">
    <div class="card">
        <div class="card-header">
            <div class="">
                @Model.Name
                <input type="hidden" asp-for="@Model.Name" />//サーバー側で受け取るため
            </div>
            <div class="">
                @Model.Age
                <input type="hidden" asp-for="@Model.Age" />//サーバー側で受け取るため
            </div>
        </div>

        <div class="card-body">
            @for (var i = 0; i < Model.Items.Count; i++)//foreachではだめ.必ずforを使うこと.
            {
                @* サーバー側に値が渡るようにするためにはInput要素であることが必要 *@
                <input type="hidden" asp-for="@Model.Items[i].Name" />//サーバー側で受け取るため
                <input type="hidden" asp-for="@Model.Items[i].Price" />//サーバー側で受け取るため

                @* bool型のプロパティをasp-forに指定すると,自動的にチェックボックスに変換される *@
                <input asp-for="@Model.Items[i].IsSelected" />
                <label asp-for="@Model.Items[i].IsSelected">
                    @Model.Items[i].Name
                </label>
            }
        </div>

        <div class="card-footer">
            <button type="submit">送信</button>
        </div>
    </div>
</form>

重要ポイント

  • <input>タグのasp-forに指定したプロパティしかサーバー側に渡されない.
  • つまり,サーバー側に渡したいプロパティは<input>タグを使うこと!
  • 表示させない隠し情報とするならtype="hidden"にする.
  • ループでチェックボックスをリスト上に作成する場合は,forを使うこと!
  • foreachではチェック操作が期待したように動作しない
  • そして選択状態もサーバー側に期待したとおりに渡らない

foreachを使った場合に生成されるHTMLをブラウザの開発者ツールでみてみると,checkboxの部分のname属性の値がどれも同じname="item.IsSelected"になっている.

<div class="card-body">

                <input type="hidden" id="item_Name" name="item.Name" value="Erazer">
                <input type="hidden" data-val="true" data-val-number="The field Price must be a number." data-val-required="The Price field is required." id="item_Price" name="item.Price" value="100">
                <input type="checkbox" data-val="true" data-val-required="The IsSelected field is required." id="item_IsSelected" name="item.IsSelected" value="true">
                <label for="item_IsSelected">
                    Erazer
                </label>
                <input type="hidden" id="item_Name" name="item.Name" value="Pencil">
                <input type="hidden" id="item_Price" name="item.Price" value="100">
                <input type="checkbox" id="item_IsSelected" name="item.IsSelected" value="true">
                <label for="item_IsSelected">
                    Pencil
                </label>
                <input type="hidden" id="item_Name" name="item.Name" value="Notebook">
                <input type="hidden" id="item_Price" name="item.Price" value="100">
                <input type="checkbox" id="item_IsSelected" name="item.IsSelected" value="true">
                <label for="item_IsSelected">
                    Notebook
                </label>
        </div>

それに対してforを使った場合は以下のように,name="Items[0].IsSelected",name="Items[1].IsSelected",name="Items[2].IsSelected"というようにリストの各要素に対応するようになっている.

<div class="card-body">
                <input type="hidden" id="Items_0__Name" name="Items[0].Name" value="Erazer">
                <input type="hidden" data-val="true" data-val-number="The field Price must be a number." data-val-required="The Price field is required." id="Items_0__Price" name="Items[0].Price" value="100">
                <input type="checkbox" data-val="true" data-val-required="The IsSelected field is required." id="Items_0__IsSelected" name="Items[0].IsSelected" value="true">
                <label for="Items_0__IsSelected">
                    Erazer
                </label>
                <input type="hidden" id="Items_1__Name" name="Items[1].Name" value="Pencil">
                <input type="hidden" data-val="true" data-val-number="The field Price must be a number." data-val-required="The Price field is required." id="Items_1__Price" name="Items[1].Price" value="100">
                <input type="checkbox" data-val="true" data-val-required="The IsSelected field is required." id="Items_1__IsSelected" name="Items[1].IsSelected" value="true">
                <label for="Items_1__IsSelected">
                    Pencil
                </label>
                <input type="hidden" id="Items_2__Name" name="Items[2].Name" value="Notebook">
                <input type="hidden" data-val="true" data-val-number="The field Price must be a number." data-val-required="The Price field is required." id="Items_2__Price" name="Items[2].Price" value="100">
                <input type="checkbox" data-val="true" data-val-required="The IsSelected field is required." id="Items_2__IsSelected" name="Items[2].IsSelected" value="true">
                <label for="Items_2__IsSelected">
                    Notebook
                </label>
        </div>

このようにforとforeachでは生成されるHTMLが異なることが理由で,forじゃないと値がサーバー側に渡らない.

ソースコード

github.com