ASP.NET MVC オートコンプリート
概要
あると便利!jQuery UIのAutocomplete(オートコンプリート)をASP.NET MVCで実装してみます。
今回のサンプルは入力した文字列に応じて入力候補が表示され、選択した値が各項目にセットされるというものです。
環境
Visual Studio Community 2015 Update 2
ASP.NET MVC5
jQuery UI
実装
コントローラー
必要なのはJSONデータなので、JsonメソッドによりJsonResultオブジェクトを返します。
既定ではHTTP GETリクエストではJSONデータを返せないようです。
Controllers\HomeController.cs
//ビューの表示 public ActionResult Create() { return View(); } public JsonResult AutoComplete(String name) { var data = _service.GetPeopleByName(name); return Json(data); }
明示的にGETリクエストを許可するには以下のようにする必要があります。
return Json(data, JsonRequestBehavior.AllowGet);
ワーカーサービス
多くの場合、リポジトリクラスからデータベースにアクセスし必要なデータを取得すると思いますが、今回はサンプルのため擬似コードで割愛。
Services\People\PeopleService.cs
public class PeopleService : IPeopleService { public IEnumerable<Person> GetPeopleByName(string name) { var data = GetData(); var result = data.Where(c => c.Name.StartsWith(name, ignoreCase: true, culture: ci)); return result; } }
モデル
Personクラスをベースにします。
Models\Person.cs
public class Person { public int Id { get; set; } public String Name { get; set; } public String Email { get; set; } public String Birthday { get; set; } }
ビュー
簡単な入力フォーム上でName項目に入力した値で動作するようにしています。
Views\Home\Create.cshtml
@using (Html.BeginForm()) { @Html.AntiForgeryToken() <div class="form-horizontal"> <h4>Person</h4> <hr /> @Html.ValidationSummary(true, "", new { @class = "text-danger" }) <div class="form-group"> @Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.Email, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Email, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Email, "", new { @class = "text-danger" }) </div> </div> <div class="form-group"> @Html.LabelFor(model => model.Birthday, htmlAttributes: new { @class = "control-label col-md-2" }) <div class="col-md-10"> @Html.EditorFor(model => model.Birthday, new { htmlAttributes = new { @class = "form-control" } }) @Html.ValidationMessageFor(model => model.Birthday, "", new { @class = "text-danger" }) </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> }
$(function () { $('#Name').autocomplete({ source: function (request, response) { var param = { name: $('#Name').val() }; $.ajax({ url: '@Url.Content("~/Home/AutoComplete")', data: JSON.stringify(param), datatype: "json", type: "POST", contentType: "application/json", dataFilter: function (data, type) { return data }, success: function (data, dataType) { response($.map(data, function (item) { return { label: "ID:" + item.Id + " Name:" + item.Name + " Email:" + item.Email + " Birthday:" + item.Birthday, value: item.Name, extend: item }; })); }, error: function (XMLHttpRequest, textStatus, errorThrown) { alert('error'); } }); }, select: function (event, ui) { $('#Email').val(ui.item.extend.Email); $('#Birthday').val(ui.item.extend.Birthday); } }); });
実行結果
Name項目に入力した文字列に対して入力候補が絞られていきます。
最終的に選択した値が各項目にセットされました!
ASP.NET Web APIという選択
ASP.NET MVCはRPCベースのスタイルであるのに対し、ASP.NET Web APIはRESTfullスタイルが既定(RPCもイケル)です。
ASP.NET MVCではJSONデータが返せるため、あまりメリットを感じないのですが、本来はWeb APIとして提供した方がいいケースもあります。
実装
APIコントローラー
MVC6では統合されたようですが、今回はMVC5なのでASP.NET Web APIコントローラーはまだSystem.Web.HttpアセンブリのApiControllerを継承しています。
Api\PeopleController.cs
public class PeopleController : ApiController { public IEnumerable<Person> GetByName(String name) { return _service.GetPeopleByName(name); } }
プロジェクト作成時にテンプレートでWeb APIを選択していない場合、APIコントローラーを追加しただけでは動かないため、以下を追加します。
既定のルートの設定
App_Start\WebApiConfig.cs
public static class WebApiConfig { public static void Register(HttpConfiguration config) { config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); } }
Web APIの既定ルートを登録
Global.asax
protected void Application_Start() { //追記 GlobalConfiguration.Configure(WebApiConfig.Register); ... }
ビュー
GETリクエストでhttp://{server}/api/{apicontroller}へアクセスしJSONデータを取得します。
JavaScript
$(function () { $('#Name').autocomplete({ source: function (request, response) { var param = { name: $('#Name').val() }; $.getJSON('@Url.Content("~/api/people")', param) .done(function (data) { response($.map(data, function (item) { return { label: "ID:" + item.Id + " Name:" + item.Name + " Email:" + item.Email + " Birthday:" + item.Birthday, value: item.Name, extend: item }; })); }) .fail(function (jqXHR, textStatus, err) { alert('error : ' + err); }); }, select: function (event, ui) { $('#Email').val(ui.item.extend.Email); $('#Birthday').val(ui.item.extend.Birthday); } }); });
まとめ
見た目は同じですが、実装をASP.NET Web APIに変更してみました。
どちらを選択するかは仕様によると思いますが、MVC6で統合された経緯を見る限りどちらも使いこなせたほうが良さそうですね。
ASP.NET Coreを視野に入れつつASP.NET Web APIも学習してみようっと。
参考
プログラミングASP.NET MVC 第3版 ASP.NET MVC 5対応版
- 作者: ディノエスポシト
- 出版社/メーカー: 日経BP社
- 発売日: 2015/11/18
- メディア: Kindle版
- この商品を含むブログを見る
.NET開発テクノロジ入門 2014年版 VisualStudio2013対応版 (MSDNプログラミングシリーズ)
- 作者: 酒井達明,山田祥寛,小高太郎,中原幹雄,芝村達郎,和田健司,日本マイクロソフト株式会社エバンジェリストチーム
- 出版社/メーカー: 日経BP社
- 発売日: 2014/06/04
- メディア: 単行本
- この商品を含むブログ (6件) を見る