書籍転載:ASP.NET MVC 5 実践プログラミング

書籍転載:ASP.NET MVC 5 実践プログラミング

テンプレートのカスタマイズ|テンプレートを決定する方法[Razor]

2014年11月4日

テンプレートヘルパーでは、特定のデータ型/メタ情報に応じた独自のテンプレートを用意して、独自の出力を生成することもできる。その方法を解説する。書籍転載の16本目(基礎編「4-4-2」「4-4-3」)。

  • このエントリーをはてなブックマークに追加

書籍転載について

 本コーナーは、秀和システム発行の書籍『ASP.NET MVC 5 実践プログラミング』の中から、特にBuild Insiderの読者に有用だと考えられる項目を編集部が選び、同社の許可を得て転載したものです。

 

 『ASP.NET MVC 5 実践プログラミング』の詳細や購入は秀和システムのサイト目次ページをご覧ください。

ご注意

 本記事は、書籍の内容を改変することなく、そのまま転載したものです。このため用字用語の統一ルールなどはBuild Insiderのそれとは一致しません。あらかじめご了承ください。

4-4-2 テンプレートのカスタマイズ

 テンプレートヘルパーでは、標準のテンプレートを利用するばかりではありません。特定のデータ型/メタ情報に応じて、独自のテンプレートを用意することで、独自の出力を生成することもできるのが、テンプレートヘルパーの本来の魅力です。

 たとえば以下は、DateTime型のプロパティに対して、EditorForメソッドがポップアップカレンダー付きのテキストボックスを出力するための例です*25。ポップアップカレンダーの実装には、jQuery UI(8-2-4項=転載対象外)のDatepickerウィジェットを利用します。

  • *25 HTML5の<input type="date">要素でも同様のUIを実装できます。ただし、HTML5に対応していないブラウザーもまだまだ現役であることを考慮すると、jQuery UIを利用するのが無難です。
図4-7 [公開日]欄にフォーカスを移動すると、カレンダーをポップアップ

図4-7 [公開日]欄にフォーカスを移動すると、カレンダーをポップアップ

 以下に、具体的な手順を追っていきます。

1EditorForメソッドのためのテンプレートを準備する

 EditorForメソッドのテンプレートは、以下のパスに従って配置します*26

  • *26 本項ではEditorForを対象に手順を説明しますが、DisplayForメソッドでも、テンプレートの配置先が「~/Views/Shared/DisplayTemplates」「~/Views/コントローラー名/DisplayTemplates」になるだけで、以降の手順は同様です。
  • ~/Views/Shared/EditorTemplates/Xxxxx.cshtml … アプリケーション全体で有効
  • ~/Views/コントローラー名/EditorTemplates/Xxxxx.cshtml … 特定のコントローラーでのみ有効

 Xxxxxの部分には型名、もしくはUIHint属性で指定するビュー名を指定します。EditorForメソッドは「UIHint属性→DataType属性→データ型」の優先順で、対応するテンプレートを検索します。

 ここでは、「アプリケーション共通でDateTime型のプロパティに対応する」テンプレートを定義したいので、「~/Views/Shared/EditorTemplates/DateTime.cshtml」というテンプレートを用意します。

 具体的なコードは、以下のとおりです。

Razor
@model System.DateTime?

@Html.TextBoxFor(model => model, new { @class = "form-control cal" })
リスト4-26 Views/Shared/EditorTemplates/DateTime.cshtml

 @modelディレクティブで宣言されている型が「System.DateTime?」である点に注目してください*27。EditorForメソッドによる呼び出しでは、テンプレートに渡されるモデルも(エンティティそのものではなく)プロパティだからです。よって、テンプレート配下のTextBoxForメソッドでも「model => model.プロパティ」ではなく、「model => model」のように表します。

  • *27 null許容型になっているのは、新規登録画面(Create.cshtml)ではnull値が渡されるからです。

 なお、TextBoxForメソッドでclass属性を指定しているのは、あとからjQuery UIでdatepickerメソッドを呼び出す際のキーとするためです*28。これで$('.cal').datepicker()のようにすることで、テキストボックスにカレンダー機能を付与できます。

  • *28 もちろん、対応関係がとれていれば、class属性には別の名前を指定しても構いません。

【Note】EditorForメソッドのパラメーターを引用する

 EditorForメソッドから任意のHTML属性を渡すこともできます。

Razor
@Html.EditorFor(model => model.Published,
  new { htmlAttributes = new { @class = "form-control cal" } })

 この場合、テンプレート側では、ビュー変数としてこれを受け取ります。

Razor
@Html.TextBoxFor(model => model, (object)ViewBag.htmlAttributes)

 もしもテンプレート側で新たな属性を追加したいならば、以下のようにします。AnonymousObjectToHtmlAttributesは、匿名型をIDictionary<string,object>型に変換するためのメソッドです。

Razor
@{
  var attr = HtmlHelper.AnonymousObjectToHtmlAttributes((object)ViewBag.htmlAttributes);
  attr.Add("tabindex", "5");  // tabindex 属性を追加
}
@Html.TextBoxFor(model => model, attr)
2jQuery UIライブラリをインポートする

 jQuery UIを利用するには、あらかじめjQuery UIの関連リソースをプロジェクトに組み込んだ上で、レイアウトからインポートしなければなりません。具体的な方法については8-2-4項(転載対象外)で詳説していますので、そちらを参照してください。ここでは、jQuery UIの本体に加えて、カレンダー呼び出しのコードもインポートしておきます。

JavaScript
$(function () {
  //「class="cal"」である要素にカレンダー機能を付与
  $('.cal').datepicker();
});
リスト4-27 Scripts/app.js
C#
bundles.Add(new ScriptBundle("~/bundles/jqueryui").Include(
  "~/Scripts/jquery-ui-{version}.js",
  "~/Scripts/app.js"));
リスト4-28 App_Start/BundleConfig.cs

 これで「~/bundles/jqueryui」というパスで、jQuery UI共々、app.jsがインポートされ、カレンダー機能が有効になりました。

3テンプレートの動作を確認する

 以上で、自作テンプレートを有効にする手順は完了です。先ほどScaffolding機能で作成したアプリケーションを動作してみましょう。[公開日]欄にフォーカスを移動すると、冒頭の図4-7のように、ポップアップカレンダーが表示されることを確認してください。

4-4-3 テンプレートを決定する方法

 先ほども触れたように、テンプレートヘルパーはあらかじめ決められた優先順位に従って、呼び出すべきテンプレートを決定します。以下に、優先順位が低い順にその方法をまとめます。

(1)標準のデータ型

 前項で触れている方法です。PublishedプロパティはDateTime型なので、DateTime.cshtmlを選択します。

(2)付随的なデータ型(DataType属性)

 たとえばPublishedプロパティに、以下のようなDataType属性を付与した場合、(DateTime.cshtmlではなく)Date.cshtmlを選択します*29

  • *29 動作を確認する際には、DateTime.cshtmlをリネームするなどしてください。
C#
[DisplayName("公開日")]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:yyyy年MM月dd日}")]
public DateTime Published { get; set; }
リスト4-29 Models/Article.cs
(3)利用するテンプレートを宣言(UIHint属性)

 UIHint属性を利用することで、任意のテンプレートを紐づけることができます。たとえば、以下はPublishedプロパティにCalendar.cshtmlを関連付ける例です。通常は(2)までで賄えるのが理想ですが、特定のプロパティに対してのみ適用したいテンプレートを宣言する際には、この方法を利用します。

C#
[DisplayName("公開日")]
[UIHint("Calendar")]
[DisplayFormat(DataFormatString = "{0:yyyy年MM月dd日}")]
public DateTime Published { get; set; }
リスト4-30 Models/Article.cs
(4)テンプレートヘルパーの引数

 テンプレートヘルパーの第2引数で、明示的にテンプレートを指定することもできます。同一のプロパティには同じテンプレートを関連付けるのがまず基本ですので、まずはの(3)方法で賄えないかを検討してください。

 以下は、Publishedプロパティに対して、CustomCal.cshtmlを関連付ける例です。

Razor
@Html.EditorFor(model => model.Published, "CustomCal", new { @class = "form-control" })
リスト4-31 Views/Articles/Edit.cshtml

※以下では、本稿の前後を合わせて5回分(第14回~第18回)のみ表示しています。
 連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。

14. HTMLエンコードを無効にする - Html.Rawメソッド[Razor]

デフォルトで実行されるHTML予約文字のエスケープ処理を無効にして生のままHTMLコードを出力するためのHtml.Rawメソッドについて解説。書籍転載の14本目(基礎編「4-3-4」)。

15. テンプレート関連のビューヘルパー|テンプレートの標準の挙動[Razor]

「テンプレートヘルパー」とも呼ばれるDisplayFor/EditorForメソッドについて紹介。また、テンプレートヘルパーの標準的な挙動を確認する。書籍転載の15本目(基礎編「4-4-1」)。

16. 【現在、表示中】≫ テンプレートのカスタマイズ|テンプレートを決定する方法[Razor]

テンプレートヘルパーでは、特定のデータ型/メタ情報に応じた独自のテンプレートを用意して、独自の出力を生成することもできる。その方法を解説する。書籍転載の16本目(基礎編「4-4-2」「4-4-3」)。

17. モデル単位にテンプレートを決定する - DisplayForModel/EditorForModelメソッド[Razor]

プロパティ単位ではなくモデル単位でHTMLコードを出力するDisplayForModel/EditorForModelメソッドについて解説。また、そのテンプレートを自作する方法を説明する。書籍転載の17本目(基礎編「4-4-4」)。

18. LINQとは?[C#]

LINQ to Entitiesの説明に入る前に、まずはC#の言語機能として組み込まれたクエリ機能「LINQ」について簡単に紹介する。書籍転載の18本目(基礎編「5-3-1」)。

サイトからのお知らせ

Twitterでつぶやこう!