[ASP.NET][DropDownList][AutoComplete]改寫DropDownList下拉式選單改成ComboBox並可以輸入搜尋(AutoComplete)讓他更容易使用

小喵在開發某個系統的時候,使用者提到,某個下拉選單的選項很多,點下拉後要拉來拉去的找好久,有沒有可以像Google搜尋一下,輸入的時候,自動找出符合的,來加快選擇。小喵立馬想到『DropDownList jQuery AutoComplete』這些關鍵字。果然找到jQuery UI中有個Autocomplete ComboBox很合適。
過程中,小喵稍微改寫一下使用的方式,讓我套用變得更容易些。

緣起

小喵在開發某個系統的時候,使用者提到,某個下拉選單的選項很多,點下拉後要拉來拉去的找好久,有沒有可以像Google搜尋一下,輸入的時候,自動找出符合的,來加快選擇。小喵立馬想到『DropDownList jQuery AutoComplete』這些關鍵字。果然找到jQuery UI中有個Autocomplete ComboBox很合適。
​過程中,小喵稍微改寫一下使用的方式,讓我套用變得更容易些。

jQuery UI AutoComplete ComboBox

先來看看官方的說明頁

https://jqueryui.com/autocomplete/#combobox

說明一下課題點:

  1. 官方說明頁中,有關CSS的設定與JS的部分,其實可以收編起來,分別用一個CSS與JS
  2. 官方的程式碼是使用id的Selector,但是如果畫面中有許多的DropDownList都要做類似的處理,這樣不是很好寫
    這部分可以用『自訂的屬性方式』來處理,這樣多個要有效果,會比較容易處理。

實際範例

DropDownList2ComboBox.css

首先,先把官方的那一段CSS的設定,另存成一個CSS檔案,就命名為『DropDownList2ComboBox.css』,相關內容如下:

.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;
    width: 480px;
}
.ui-autocomplete {
    z-index: 2147483647;
}

說明,其中的『.ui-autocomplete』這段是官方沒有另外加上的,原因是小喵搭配 Bootstrap 4 的 Modal使用時,他的下拉選單會被 Modal 蓋住,所以把他的z-index調整到最上方。

DorpDownList2ComboBox.js

另外,官網說明中,加上的相關Javascript語法,小喵也把他集中到一個js檔,方便之後直接引用,相關內容如下:

$(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", "")
                .addClass("custom-combobox-input ui-widget ui-widget-content ui-state-default ui-corner-left")
                .autocomplete({
                    delay: 0,
                    minLength: 0,
                    source: $.proxy(this, "_source")
                })
                .tooltip({
                    classes: {
                        "ui-tooltip": "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", "Show All Items")
                .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")
                .on("mousedown", function () {
                    wasOpen = input.autocomplete("widget").is(":visible");
                })
                .on("click", function () {
                    input.trigger("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) {
                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", value + " didn't match any item")
                .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();
        }
    });

    $('select[data-Combo="Y"]').combobox();

});

說明:其中的最後一句『$('select[data-Combo="Y"]').combobox();』

原本的官方是使用 id 的方式來加上功能,但是當您畫面有許多個 DropDownList 都需要這樣做,就會寫了好幾個。仔細的去分析一下,DropwDownList會產生的是『select option』的html tag,我們藉由『自訂屬性』的方式,讓DropDownList要加上這樣的功能,只需要在DropDownList中,加上自訂的屬性『data-Combo="Y"』,這樣該 DropDownList 就會套用功能。這樣要套用就方便多了。

剩下的,就是原本需要的東西,這裡不在特別提出。

接著就是我們的aspx要怎麼應用呢?,請看以下的範例:

首先,在aspx的head部分,加上以下這些引用

    <link href="/MyPrj/Content/jquery-ui.css" rel="stylesheet" />
    <link href="/MyPrj/Content/DorpDownList2ComboBox.css" rel="stylesheet" />
    <script src="/MyPrj/Scripts/jquery-ui.js"></script>
    <script src="/MyPrj/JS/DropDownList2ComboBox.js"></script>

然後,就是在需要套用的 DropDownList 上面,加上自訂的屬性『data-Combo="Y"』,例如以下這樣:

<asp:DropDownList ID="DropDownList1" runat="server" data-Combo="Y" DataSourceID="ods1" DataTextField="TextField" DataValueField="ValueField"></asp:DropDownList>

就醬子,就可以讓 DropDownList ,有等同jQuery UI 中 AutoComplete ComboBox 的效果。

 

小喵將相關的設定在這邊筆記一下,也提供有需要的網友參考。

^_^

 

 

 


以下是簽名:


Microsoft MVP
Visual Studio and Development Technologies
(2005~2019/6)