井上です。
ASP.NET Webフォームのドロップダウンコントロールでオートコンプリートをやろうというお話です。
ちょっとと面倒だったのでまとめておきます。
環境
.NET Framework 4.5.1
ASP.NET Web Form
C#
参考
やりたいこと
オートコンプリート化したいDropDownListコントロールを含むページで、お手軽にオートコンプリート化させる
コード
オートコンプリート関数の作成(jquery.autocomplete.js)
;(function ($) { $.fn.autocompleteExtend = function () { return this.each(function() { $.widget("custom.combobox", { _create: function () { this.wrapper = $("<span>") .addClass("custom-combobox") .insertAfter(this.element); this.element.hide(); this._createAutocomplete(); this._createShowAllButton(); }, _createAutocomplete: function () { var selected = this.element.children(":selected"), value = selected.val() ? selected.text() : ""; this.input = $("<input>") .appendTo(this.wrapper) .val(value) .attr("title", "") .attr("onKeydown", "return InvalidInput(event)") // enterキーの挙動を打ち消す .attr("style", "float:left;") // ブラウザ差異対応 .addClass("custom-combobox-input ui-widget ui-widget-content ui-state-default ui-corner-left autocomplete") .autocomplete({ delay: 0, minLength: 0, source: $.proxy(this, "_source") }) .tooltip({ tooltipClass: "ui-state-highlight" }); this._on(this.input, { autocompleteselect: function (event, ui) { ui.item.option.selected = true; this._trigger("select", event, { item: ui.item.option }); }, autocompletechange: "_removeIfInvalid" }); }, _createShowAllButton: function () { var input = this.input, wasOpen = false; $("<a>") .attr("tabIndex", -1) .attr("title", "") .tooltip() .appendTo(this.wrapper) .button({ icons: { primary: "ui-icon-triangle-1-s" }, text: false }) .removeClass("ui-corner-all") .addClass("custom-combobox-toggle ui-corner-right autocomplete") .mousedown(function () { wasOpen = input.autocomplete("widget").is(":visible"); }) .click(function () { input.focus(); // Close if already visible if (wasOpen) { return; } // Pass empty string as value to search for, displaying all results input.autocomplete("search", ""); }); }, _source: function (request, response) { var matcher = new RegExp($.ui.autocomplete.escapeRegex(request.term), "i"); response(this.element.children("option").map(function () { var text = $(this).text(); if (this.value && (!request.term || matcher.test(text))) return { label: text, value: text, option: this }; })); }, _removeIfInvalid: function (event, ui) { // Selected an item, nothing to do if (ui.item) { // 選択値でポストバックさせる setTimeout('__doPostBack(\' + $(this).attr("name") + \' ,\'\')', 0); return; } // Search for a match (case-insensitive) var value = this.input.val(), valueLowerCase = value.toLowerCase(), valid = false; this.element.children("option").each(function () { if ($(this).text().toLowerCase() === valueLowerCase) { this.selected = valid = true; return false; } }); // Found a match, nothing to do if (valid) { return; } // Remove invalid value this.input .val("") .attr("title", "") .tooltip("open"); this.element.val(""); this._delay(function () { this.input.tooltip("close").attr("title", ""); }, 2500); this.input.autocomplete("instance").term = ""; }, _destroy: function () { this.wrapper.remove(); this.element.show(); } }); // 挙動設定 $('#' + $(this).attr("id") ).combobox(); // ドロップダウンのスクロール指定 $('.ui-autocomplete').css('overflow-y', 'auto'); $('.ui-autocomplete').css('overflow-x', 'hidden'); $('.ui-autocomplete').css('height', '200px'); }); } })(jQuery); $(function () { $(".autocomplete").autocompleteExtend(); });
参考先のコードを元に作成。
入力値/選択値がリスト内の要素と完全一致するときのみポストバックさせます。
また動的に生成されるドロップダウンのスクロール指定等を行っています。
最後の処理はautocomplete
クラスを持つ要素に対してautocompleteExtend
を呼び出すためのものです。
呼び出し元コード(sample.aspx)
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="sample.aspx.cs" Inherits="WebApplication1.sample" %> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <title></title> <script src="Scripts/jquery-1.12.4.min.js"></script> <script src="Scripts/jquery-ui-1.12.0.min.js"></script> <script src="Scripts/jquery.autocomplete.js"></script> <link rel="stylesheet" href="Content/themes/base/jquery-ui.min.css" /> <style> .custom-combobox { position: relative; display: inline-block; } .custom-combobox-toggle { position: absolute; top: 0; bottom: 0; margin-left: -1px; padding: 0; } .custom-combobox-input { margin: 0; padding: 5px 10px; } </style> </head> <body> <form id="form1" runat="server"> <div> <asp:DropDownList ID="HogeHogeList" runat="server" OnSelectedIndexChanged="HogeHogeList_SelectedIndexChanged" AutoPostBack="true" CssClass="autocomplete"></asp:DropDownList> </div> </form> </body> </html>
DropDownListコントロールにautocomplete
クラスを指定しているのみです。
呼び出し元コード(sample.aspx.cs)
using System; using System.Collections.Generic; namespace WebApplication1 { public partial class sample : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { var list = new Dictionary<string, string> { { "", "0" }, { "Aゴルフ場", "1" }, { "Bカントリー倶楽部", "2" }, { "Cゴルフコース", "3" }, { "Dカントリークラブ", "4" }, { "Eゴルフリゾート", "5" } }; this.HogeHogeList.DataSource = list; this.HogeHogeList.DataTextField = "Key"; this.HogeHogeList.DataValueField = "Value"; this.HogeHogeList.DataBind(); } } protected void HogeHogeList_SelectedIndexChanged(object sender, EventArgs e) { // 選択時の処理 } } }
実行すると
入力すると一致する候補がきっちり表示されます。
リストから選択すればSelectedIndexChangedイベントが発生します。