何だかんだで一番苦労するのがフォームを作成する時なので、後から見て思い出せるように Tag Helpers を使って書く時の基本的なメモをまとめておきます。
ASP.NET Core MVC 2.0 以降は Razor がアップデートされて変わりそうですが、とりあえず 1.1 対象で。
asp-for は Expression 扱い
Visual Studio で書いている時には文字列にしか見れないですが、Tag Helpers の asp-for は式になってるので単純なプロパティ名だけじゃなくて、複雑な式も指定することが出来ます。
Mvc/InputTagHelper.cs at c27b07ef3f8b07dfe1d1de38a8d7bf2d6a9298f4 · aspnet/Mvc · GitHub
なので Html Helper と同じように式を書けます。移行も比較的簡単に行えそうです。
@Html.TextBoxFor(m => m.Product[0].Name) <input type="text" asp-for="Product[0].Name" />
実際に出力された HTML は以下の通りです。ちゃんと意図した通りの結果になっています。
最近は配列を使う場面は少ないと思いますが、構造化されたモデルを使うことはあると思うので、そういう場合にも Tag Helper を使うとシンプルに書くことが出来ます。
クライアントサイド検証を無効にする
ASP.NET Core MVC のデフォルトでは jQuery Validation などを使ったクライアントサイド検証が有効化されています。試しに以下のような Razor を書いて実行してみます。
<form asp-controller="User" asp-action="Login" method="post"> <div asp-validation-summary="ModelOnly"></div> <input asp-for="Email" /> <span asp-validation-for="Email"></span> <input asp-for="Password" /> <span asp-validation-for="Password"></span> <button>Login</button> </form>
出力された HTML には data-* 属性を使ったエラーメッセージが埋め込まれています。
クライアントサイド検証が必要ない場面もあるので、そういった時には Startup クラスで無効化することが出来ます。このオプションはちょっとわかりにくい場所にあります。
AddMvc の後に AddViewOptions を追加して ClientValidationEnabled を false にします。
public void ConfigureServices(IServiceCollection services) { // Add framework services. services.AddMvc() .AddViewOptions(options => { options.HtmlHelperOptions.ClientValidationEnabled = false; }); }
Tag Helper を使っていても HtmlHelperOptions なのは少し違和感がありますが、この設定を入れた後に HTML を確認すると data-* 属性が出力されなくなったことが確認できます。
エラーメッセージ表示用の span だけは残るのが気になります。本来なら要らないはずです。
select に Enum を利用する
ASP.NET MVC には EnumDropDownListFor という Html Helper がありますが、Tag Helper には該当する機能がないので Html.GetEnumSelectList<TEnum> を使って SelectListItem を作成します。
enum に対しては Display 属性を使って表示用の名前を追加することが出来ます。
public enum ProductKind { [Display(Name = "オプション1")] Option1, [Display(Name = "オプション2")] Option2, [Display(Name = "オプション3")] Option3 }
実際に Tag Helper で使う場合には大体以下のようになると思います。asp-items に SelectListItem のコレクションを指定すると、いい感じに出力してくれます。
<select asp-for="Products[0].Kind" asp-items="Html.GetEnumSelectList<ProductKind>()"></select>
ブラウザでの表示は以下のようになります。asp-for で指定したプロパティに値を設定しておけば、その項目が予め選択された状態になるので便利です。
複数選択の場合などは自前で SelectListItem を作る必要がありそうです。
Radio Button を利用する
ASP.NET MVC 5 の頃から作りにくかった Radio Button ですが、Core MVC でも状況はあまり変わっていないようでした。type = radio の場合には asp-for 以外に value の設定が必須です。
生成される id が全て同じ値になってしまうのもこれまで通りです。なので label の for 属性で指定することは出来ないので、label で input を囲んでしまいます。
<label> Option1 <input type="radio" asp-for="Products[0].Kind" value="@(ProductKind.Option1)"/> </label> <label> Option2 <input type="radio" asp-for="Products[0].Kind" value="@(ProductKind.Option2)" /> </label> <label> Option3 <input type="radio" asp-for="Products[0].Kind" value="@(ProductKind.Option3)" /> </label>
これで一応 Radio Button としては動作してくれます。asp-for で指定したプロパティに値を設定しておくと、ちゃんとチェックが入った状態になります。
今の Html Helper や Tag Helper の範囲では良い解決策が無さそうなので、これまで通り自前でガリガリ HTML を書くか専用の Tag Helper を用意するかしか方法はなさそうです。
個人的には Web Forms の Repeater みたいな Tag Helper があれば解決しそうだと思いました。
関係ないですが、Damian 氏の TagHelperPack が結構面白かったので紹介しておきます。