舊的那篇寫的太多太亂,而且 Github 上的 example 有點問題,所以重做一篇。
View
- @using CircleHsiao.Demo.JQueryUiCombobox.ViewModels
- @model JQueryUiComboboxViewModel
- @{
- ViewBag.Title = "JQuery UI Combobox Demo";
- }
- <div class="row">
- <h2>JQuery UI Combobox Demo</h2>
- <div class="col-md-12">
- @using (Html.BeginForm()) {
- <p>Selected Value: @Html.DisplayFor(m => m.SelectedValue)</p>
- <p>@Html.DropDownListFor(m => m.SelectedValue, @Model.Options)</p>
- <button>submit</button>
- }
- </div>
- </div>
ViewModel
要用 DropDownListFor 的話要做 ViewModel,不然用 DropDownList 就好。
- public class JQueryUiComboboxViewModel
- {
- public IEnumerable<SelectListItem> Options { get; set; }
- public string SelectedValue { get; set; }
- }
Controller
這裡需要注意的是 Post 回來的 ViewModel 裡 Options 的狀態會流失,似乎回傳集合資料要自己做成 json 之類回來轉換,這個之後研究。
- public class HomeController : Controller
- {
- private static readonly List<SelectListItem> _options = new List<SelectListItem>()
- {
- new SelectListItem() { Text = "option1", Value = "1" },
- new SelectListItem() { Text = "option2", Value = "2" },
- new SelectListItem() { Text = "option3", Value = "3" }
- };
- public ActionResult Index()
- {
- var vm = new JQueryUiComboboxViewModel();
- vm.Options = _options;
- return View(vm);
- }
- [HttpPost]
- public ActionResult Index(JQueryUiComboboxViewModel vm)
- {
- var selectedVal = vm.SelectedValue;
- vm.Options = _options;
- return View(vm);
- }
- }
好了之後用 Nuget 載 JQuery UI。
https://jqueryui.com/autocomplete/#combobox
因為很多頁都有機會用到,建議就把它做成獨立的 js 跟 css,再跟 jquery-ui 打成一包。
jquery-ui-combobox.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;
- }
jquery-ui-combobox.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();
- }
- });
- })(jQuery);
然後 BundleConfig.cs
- public static void RegisterBundles(BundleCollection bundles)
- {
- bundles.Add(new ScriptBundle("~/bundles/jquery-ui").Include(
- "~/Scripts/jquery-ui-1.12.1.min.js",
- "~/Scripts/jquery-ui-combobox.js"));
- bundles.Add(new StyleBundle("~/Content/jquery-ui-css").Include(
- "~/Content/themes/base/jquery-ui.min.css",
- "~/Content/jquery-ui-combobox.css"));
- }
再到 _Layout.cshtml 加上 Render
- <html>
- <head>
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>@ViewBag.Title - My ASP.NET Application</title>
- @Styles.Render("~/Content/css")
- @Styles.Render("~/Content/jquery-ui-css") //
- @Scripts.Render("~/bundles/modernizr")
- </head>
- <body>
- // skip
- @Scripts.Render("~/bundles/jquery")
- @Scripts.Render("~/bundles/bootstrap")
- @Scripts.Render("~/bundles/jquery-ui") //
- @RenderSection("scripts", required: false)
- </body>
- </html>
最後回到 View
為 DropDownList 加上 class="cutomer-combobox" 並補上
- @Html.DropDownListFor(m => m.SelectedValue, @Model.Options, new { @class = "custom-combobox" })
就完成了。
- @section scripts{
- <script>
- $(function () {
- $(".custom-combobox").combobox();
- });
- </script>
- }
補個取值
- $(".custom-combobox").combobox({
- select: function (event, ui) {
- console.log(ui.item.text);
- console.log(ui.item.value);
- }
- });
Github: Demo
沒有留言:
張貼留言