検証付きドロップダウンリストを実装する
ドロップダウンリスト(あるいは、DropDownList、セレクトリスト、SelectList、コンボボックス、ComboBox とも言う)の実装は、ASP.NET MVC を初めた 90 % の人がググるであろう、最初のハードルです。
今回は、ドロップダウンリストの実装例を検証機能も含めて紹介します。
- 概要
- HTTP のやりとり
- ドロップダウンリスト実装のポイント
- ドロップダウンリストの表示
- ドロップダウンリストの HTML
- 選択した値をモデルバインドさせる
- 検証エラーで再表示するときも忘れずに
- 補足
- 実装手順
概要
GET:~/Person/Create で次のような画面を表示します。色を選択できるドロップダウンリストが含まれています。
名前と好きな色、どちらかを入力・選択しないで Create ボタンを押すと、次のようにエラーメッセージが表示されます。(好きな色を”選択して下さい”にしても、エラーメッセージが表示されます。)
名前と好きな色、両方を入力して Create ボタンを押すと、~/Person/CreateCompleted に遷移し、”登録完了!”というメッセージが表示されます。
JavaScript によるクライアント側の検証は行わないものとします。
(= Create ボタンを押すと、必ずサーバー側へリクエストが送信されます。)
HTTP のやりとり
ブラウザとサーバーの HTTP のやりとりを、簡単に確認します。
ポイントは、ドロップダウンリストを表示する方法と、
サーバー側からブラウザへ HTML を送信するとき―②と④の2ヵ所でドロップダウンリストを表示(用意)しなければいけないことの2つです。
このポイントについては後で説明します。
ドロップダウンリスト実装のポイント
ドロップダウンリストの実装のポイントを説明します。説明に使うコードは、次のセクション「実装」にて使用しているコードです。初めての場合や、手っ取り早く理解したい方は、ここを飛ばして「実装」を試すことをお勧めします。
ドロップダウンリストの HTML
ドロップダウンリストは、次のようにタグで表されます。
フォーム送信時には、name 属性である FavoriteColorId と、選択した項目の value 属性の値が送信されます。例えば、「あか」を選択した場合は、「FavoriteColorId=1」が送信されます。(フォーム送信の仕組みについては、WEB フォーム送信の仕組みを理解する をご覧ください。)
ここでのポイントは、選択された値―「FavoriteColorId=1」の「1」を受け取るためのクラスとプロパティを用意する必要がある、ということです。(後に登場する CreatePersonModel クラスの FavoriteColorId プロパティになります。)
ドロップダウンリストの表示
ドロップダウンリストを表示するには、Controller 側で SelectList(System.Web.Mvc 名前空間)に、選択項目のソースを格納する必要があります。
具体的には、下のようなコードになります。
今回は、選択項目のソースをデータベースから取り出すことを想定しました。(他には Enum から取り出すケースがあります。)GetColorList() メソッドで、ダミーの Color コレクションを用意しています。(実際は、データベースに接続してコレクションを用意すると思います。)
SelectList のコンストラクタの第1引数には、ソースとなるデータのコレクションを(厳密には IEnumerable 型のインスタンスを)。
第2引数には、ドロップダウンリストの value 属性の値に該当するプロパティ名を(今回の場合は、Color クラスの Id プロパティ)。
第3引数には、ドロップダウンリストの項目名(画面から確認できる”あか・き・みどり”といったテキスト)に該当するプロパティ名を(今回の場合は、Color クラスの Name プロパティ)設定します。
ビューは、次のように Html.DropDownListFor を利用します。
第1引数には、選択した値を格納(モデルバインド)したいプロパティを。
第2引数には、ドロップダウンリストのソースである SelectList のインスタンスを。
第3引数には、オプションラベル(先頭に表示される、空を表す選択項目名)を設定します。
選択した値をモデルバインドさせる
ドロップダウンリストで選択された値は、CreatePersonModel クラスの FavoriteColorId プロパティに、モデルバインドの仕組みによって格納されます。(CreatePersonModel クラスは、PersonController クラスの Create メソッドの引数に定義することにより、モデルバインドの対象となります。)
モデルのクラスでは、ドロップダウンリストの項目ソースを表す ColorSelectList プロパティと、選択した値を表す FavoriteColorId プロパティを用意することになります。
今回、FavoriteColorId の型を int の Nullable 型にした理由は、ドロップダウンリストで”選択して下さい”が選択されて送信された場合に、FavoriteColorId プロパティに null をモデルバインドさせるためです。[Required]検証属性がついているプロパティに null が代入されている場合、ASP.NET MVC の検証機構は”検証エラー”と判断します。
検証エラーで再表示するときも忘れずに
検証エラーでビューを再表示するときも、ドロップダウンリストの用意を忘れないようにします。
2回も用意するの?と不思議に思うかもしれませんが、用意しないとドロップダウンリストを表示できません。
補足
SelectList は、IEnumerable<SelectListItem> でも代用が可能です。その場合、もちろんインスタンス生成方法は変わりますが、そのまま SelectListItem のコレクションのインスタンスを生成すれば OK です。
ドロップダウンリストの実装におけるポイントは以上です。
最後に実装方法を記載して終わります。
実装
プロジェクトの用意
Visual Studio のサイト から、Visual Studio Express 2013 for Web(以下、VS Express 2013)をインストールします。無償です。
VS Express 2013 を開き、メニューから ファイル>新規作成>プロジェクト を選択します。
「ASP.NET Web アプリケーション」を選択し、OK します。ここでは、プロジェクト名を「WebApplication4」としました。(プロジェクト名は任意ですが、後のコードにてこのプロジェクト名を参照していますので、コードをコピペする時は注意。)
モデル(クラス)を用意
プロジェクトの作成が終了したら、クラスを2つ用意します。ソリューションエクスプローラーを表示しておきます。
ビュー(HTML)を描画するためのモデル、「CreatePersonModel クラス」を作成します。「Models」フォルダを右クリック>追加>クラス で「CreatePersonModel.cs」を作成します。クラスには下のようにプロパティ Name、FavoriteColorId、SelectList を用意します。
CreatePersonModel.cs
using System.ComponentModel.DataAnnotations; using System.Web.Mvc; namespace WebApplication4.Models { public class CreatePersonModel { [Required(ErrorMessage="{0} が必要です。")] [Display(Name = "名前")] public string Name { get; set; } [Required(ErrorMessage = "{0} を選択して下さい。")] [Display(Name = "好きな色")] public int? FavoriteColorId { get; set; } /// <summary> /// 色選択リスト /// </summary> public SelectList ColorSelectList { get; set; } } }
次に、ドロップダウンリストの選択アイテムの素となる「Color クラス」を作成します。先ほどと同じように「Models」フォルダに「Color.cs」クラスを作成します。プロパティは下のように Id と Name を持たせます。
Color.cs
using System; namespace WebApplication4.Models { public class Color { public int Id { get; set; } public String Name { get; set; } } }
PersonController の用意
次は、コントローラークラス「PersonController.cs」を追加します。「Controllers」フォルダを右クリックし、追加>コントローラー>MVC 5 コントローラー - 空 を選択します。
コントローラー名は「PersonController」とします。作成したら、下のようにメソッドを追加します。
PersonController.cs
using System.Collections.Generic; using System.Diagnostics; using System.Web.Mvc; using WebApplication4.Models; namespace WebApplication4.Controllers { public class PersonController : Controller { // GET: /Person/Create [HttpGet] public ActionResult Create() { //色のコレクションを取得します IEnumerable<Color> colors = GetColorList(); var model = new CreatePersonModel(); model.ColorSelectList = new SelectList(colors, "Id", "Name"); return View(model); } // POST: /Person/Create [HttpPost] public ActionResult Create(CreatePersonModel model) { if (!ModelState.IsValid) { IEnumerable<Color> colors = GetColorList(); model.ColorSelectList = new SelectList(colors, "Id", "Name"); return View(model); } //本来はここで、登録処理を行う Debug.WriteLine("Name : {0}", model.Name); Debug.WriteLine("FavoriteColorId : {0}", model.FavoriteColorId); return RedirectToAction("CreateCompleted"); } // GET: /Person/CreateCompleted [HttpGet] public ActionResult CreateCompleted() { return View(); } // 色のコレクションを取得します private IEnumerable<Color> GetColorList() { return new List<Color>() { new Color(){ Id = 1, Name = "あか"}, new Color(){ Id = 2, Name = "き"}, new Color(){ Id = 3, Name = "みどり"} }; } } }
ビューの追加
作成した PersonController クラスの Create() メソッドを右クリックし、ビューの追加を選択します。次に表示されるダイアログは、そのまま「追加」を押します。
「Person」フォルダに Create.cshtml が追加されます。
Create.cshtml のコードは下のようになります。(最初のプロジェクト名に注意)
Create.csHtml
@model WebApplication4.Models.CreatePersonModel @{ ViewBag.Title = "Create"; } <h2>Create</h2> @using (Html.BeginForm()) { <div class="form-horizontal"> <div class="form-group"> @Html.LabelFor(model => model.Name, new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.TextBoxFor(model => model.Name, new { @class = "form-control" }) @Html.ValidationMessageFor(model => model.Name) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.FavoriteColorId, new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.DropDownListFor(model => model.FavoriteColorId, Model.ColorSelectList, "選択して下さい。", new { @class = "form-control" }) @Html.ValidationMessageFor(model => model.FavoriteColorId) </div> </div> <div class="form-group"> <div class="col-md-offset-2 col-md-10"> <input type="submit" value="Create" class="btn btn-default" /> </div> </div> </div> }
次は、登録完了のビューを用意します。先ほどと同じように、PersonController クラスの CreateCompleted() メソッドを右クリックし、ビューの追加を選択し、そのまま「追加」を押します。コードは下の通りです。
@{ ViewBag.Title = "CreateCompleted"; } <h4>登録完了!</h4> @Html.ActionLink("登録へ", "Create")
以上で実装は終了です。F5 でプロジェクトをデバッグ実行し、「http://localhost:XXX/Person/Create」にアクセスし、操作を試します。