對於Kendo UI AutoComplete的Client端應用,過去的印象還停留在「提供字串陣列作為資料來源」、「指定contains、startswith、endswith進行比對」、「提示項目跟帶入欄位值都來自字串陣列」、「不能限定比對吻合項目上限」,感覺不如jQuery自動完成彈性。如以下範例:Live Demo

若要做到更特殊的比對邏輯或想限制提示筆數,倒是可用serverFiltering實現,將輸入關鍵字以AJAX方式交給伺服器端程式比對再傳回提示項目結果。但對SPA及打算包成App的情境,仰賴伺服器才能運作的自動完成有點掉漆。

最近為了專案的特殊需求,較深入了解KendoAutoComplete後,驚奇發現Kendo UI的架構比想像來得彈性,許多原以為辦不到的規格要求,並不難實現。

以下是KendoAutoComplete小露身手的花式操槍表演,展示重點包含:

  1. 股票資料以JavaScript陣列方式提供,完全在Client執行,不需伺服器端程式
    技巧:使用dataSource,可傳入物件陣列,不限定字串陣列,再以dataTextField指定取用屬性
  2. 提示區塊可指定不同寬度
    技巧:.data("kendoAutoComplete").list.width(…)可指定提示區寬度
  3. 關鍵字搜尋範圍涵蓋股票代號、中文名稱及英文名稱三個欄位
    技巧:dataSource.transport.read()可以自訂JavaScript函式進行比對,取代AJAX呼叫
  4. 提示項目呈現時,符合關鍵字的欄位(可能是代號、中文或英文三欄之一)靠左顯示,代號及中文名稱靠右顯示,關鍵字部分以紅字標示
    技巧:template參數可指定函式,接入資料物件,傳回動態組裝的HTML,完全掌控提示區顯示格式
  5. 選定提示項目時,只將股票代號填入欄位,中文名稱填入另外欄位,顯示於股票代號之後
    技巧:dataTextFiled參數指定要填入,在change事件可取得股票代號值變化,加入自訂邏輯連動其他欄位

程式碼如下:Live Demo


<!DOCTYPE html>
<html ng-app="app">
<head>
    <meta charset="utf-8">
    <title>kendoAutoComplete範例:強化版</title>
    <link href="//cdn.kendostatic.com/2014.2.716/styles/kendo.common.min.css" rel="stylesheet"/>
    <link href="//cdn.kendostatic.com/2014.2.716/styles/kendo.default.min.css" rel="stylesheet"/>
    <style>
        .hi {
            color: red;
        }
 
        .hint {
            clear: both;
        }
 
        .f-l {
            float: left;
        }
 
        .f-r {
            float: right;
        }
        .symbol {
            width: 100px;
        }
    </style>
</head>
<body ng-controller="ctrl as vm">
    <div>
        <input class="symbol" kendo-auto-complete="vm.KendoObject" 
               k-options="vm.Options" ng-model="vm.Symbol" />
        <span ng-bind="vm.Name"></span>
    </div>
    <script src="//code.jquery.com/jquery-2.1.1.min.js"></script>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.2/angular.min.js"></script>
    <script src="//cdn.kendostatic.com/2014.2.716/js/kendo.all.min.js"></script>
    <script>
        var rawData = [
    { s: '1435', c: '中福', e: 'C.F.C.Y.CORP.' },
    { s: '1437', c: '勤益', e: 'GTM' },
    { s: '1471', c: '首利', e: 'SL' },
    //...省略...
    { s: '8078', c: '華寶', e: 'CCI' },
    { s: '8101', c: '華冠', e: 'Arima Comm.' },
    { s: '8105', c: '凌巨', e: 'GiantPlus' },
    { s: '8249', c: '菱光', e: 'CSI' },
    { s: '9912', c: '偉聯', e: 'AIC' }
        ];
        var book = {};
        $.each(rawData, function(i, item) {
            book[item.s] = item;
        });
 
        function myCtrl($scope) {
            var self = this;
            self.Symbol = "";
            self.Name = "";
 
            function hiliteKeywd(str, keywd) {
                return str.replace(keywd, "<span class='hi'>" + keywd + "</span>")
            }
            self.Options = {
                dataTextField: 's',
                filter: "contains",
                template: function (item) {
                    return "<div class='hint'><span class='f-l'>" + item.match +
                        "</span><span class='f-r'>" + item.s + " " + item.c + 
                        "</span></div>";
                },
                open: function() {
                    //設定指示區寬度
                    self.KendoObject.list.width(250);
                },
                change: function() {
                    var symbol = this.value();
                    if (!symbol) 
                        self.Name = "";
                    else
                        //股票代號連動名稱
                        self.Name = book[symbol] ? book[symbol].c : "";
                },
                dataSource: {
                    serverFiltering: true,
                    transport: {
                        read: function (e) {
                            //密技:dataSource.transport可用JavaScript取代Server呼叫
                            var keywd = e.data.filter.filters[0].value;
                            //輸入數字時比對s、否則比對c或n
                            var isNum = !isNaN(keywd);
                            //設定比對筆數上限
                            var count = 0, maxCount = 10;
 
                            //共用比對函式
                            function check(item, prop) {
                                if (item[prop].indexOf(keywd) > -1) {
                                    count++;
                                    item.match = item[prop].replace(keywd,
                                        "<span class='hi'>" + keywd + "</span>");
                                    return true;
                                }
                                return false;
                            }
 
                            var res = isNum ?
                              $.grep(rawData, function (item) {
                                  if (count < maxCount && check(item, "s"))
                                      return true;
                                  else
                                      return false;
                              }) :
                              $.grep(rawData, function (item) {
                                  if (count < maxCount && 
                                      check(item, "c") || check(item, "e"))
                                      return true;
                                  else
                                      return false;
                              });
                            //將比對結果傳回
                            e.success(res);
                        }
                    }
                }
            };
        }
        angular.module("app", ["kendo.directives"])
        .controller("ctrl", myCtrl);
    </script>
</body>
</html>

補充:Kendo UI有兩個版本,Core版及Profession版。Core版免費並採Apache v2 Open Source授權;Profession版多了Grid、Charts、Editor、TreeView、Upload、Charts等元件,為付費商業元件。AutoComplete包含在Core版。

[NG系列]

http://www.darkthread.net/kolab/labs/default.aspx?m=post&t=angularjs

Comments

Be the first to post a comment

Post a comment