哥在2012年(馬英九以6,891,139票當選連任的那一年)分享了JQuery教學資源看到Auto-Complete Field with jQuery, JSON & PHP文章就讓人很興奮,那時是用PHP來做的,朋友們現在可以參考[鐵人賽Day30]使用PHP&MySQL配合jQuery UI Autocomplete實作自動完成功能,幾年之後開始用ASP.NET組件搭配C#語言來,並且用了公費花了一萬六千多去恆逸教育訓練中心上過《使用jQuery UI整合ASP.NET Web Form網站開發》,今天現學現賣就來分享一下整合jQuery UI AutoComplete Widget(自動完成小工具)使用Ajax取得伺服器資料這個部份,如果不想用jQuery UI,只想用 jQuery處理自動完成的功能,可以參考jQuery自動完成懶人包,如果你想獨力使用Javascript來做自動完成功能,那就可以考慮How to create an autocomplete input with plain Javascript。
如果你對哥所說的Javascript完全搞不懂,那就先上上JavaScript 程式設計新手村課程,不懂什麼是jQuery UI,先看看jQuery UI使用者介面設計。
對自動完成最有feel的應該就是Google 自動完成了,這個功能的正式名稱為「自動完成 Autocomplete」,所提供的搜尋建議是由系統基於各種演算法條件(包含搜尋字詞的熱門程度、使用者的搜尋記錄等)演算而來。基本上,Google 認為使用者會傾向於搜尋與多數人(尤其是具同樣搜尋偏好或在同一地理位置的人)相同的字詞,有關這個功能的開發故事,見Google 搜尋「自動完成」的開發故事。
[ads2]
圖 1:Google首頁。
像哥在Google首頁的文字方塊中,輸入『工作達』這樣的查詢關鍵字,文字方塊底下,馬上幫哥在背後偷偷下一個查詢,從遠端伺服器,下載符合查詢條件的提示字串,自動地顯示在文字方塊下方,供我做選擇,如上圖所示。
可惜就算哥選了工作達人後,還是找不到哥的工作達人(https://job.achi.idv.tw)了。
圖 1-1:Google首頁。
前面兩頁幾乎被鈴木典丈的工作達人系列套書站滿了版面,哥的部落格只能慢慢等他的訊息冷了,再看看能不能重歸Google首頁。
jQuery UI是一個建立在jQuery JavaScript函式庫上的小工具跟互動式函式庫(參考JQuery UI入門),可以說是jQuery的外掛(plug-ins),非常容易使用,新手很快就可以設計出具高互動性的網站應用程式,並搭配多種網站開發程式使用,像是微軟的ASP.NET。
jQuery UI有一個Autocomplete Widget可以設計出類似Google首頁這樣的效果。不過要設計這樣的網頁,除了jQuery UI套件之外,我們還需要撰寫一個伺服端的程式碼,每當使用者在網頁文字方塊輸入關鍵字時,私下裡在用戶端利用jQuery下查詢,叫用伺服端的程式,將滿足篩選條件的資料回傳,再透過jQuery UI,將資料動態呈現在文字方塊下方。
要設計伺服器端的程式有許多的選項可供選擇,有常用的PHP程式跟很夯的Python…,但是今天哥只會介紹如何分別使用Web Form、ASP.NET Web Service(ASMX),至於WCF服務、ASP.NET Web API及MVC Action Method等技術下次有機會再分享,來整合jQuery UI Autocomplete Widget實作自動完成功能。
使用Web Form設計伺服端程式
使用開發工具:Microsoft Visual Studio Professional 2017
[ads2]
版本:.NET Framework 4.7.2
接下來我們會分享兩種建置專案的方式,來測試這個jQuery UI Autocomplete Widget的使用:
第一種是Web Site Project(WSP)的方式
這種方式是常在資策會、恆逸這種貴的要命的補習班中教師會用的方式,後面大部分的程式範例也會使用此種專案方式來分享。我們先從使用Web Form(附檔名為aspx的檔案)當做伺服端程式開始說起。接下來的步驟將使用Visual Studio 2017的Web Site的方式來建立網站。啟動Visual Studio 2017開發環境,從 Visual Studio 2017的主選單點選「檔案(F)」-「新增(N)」-「新增專案(P)」選項,接著會開啟「新增專案」對話窗,選取Visual C# – Web – 先前的版本的「ASP.NET 空白網站」,設定名稱為autodemo,位置自己選,方案名稱為autodemo,請參考下圖所示:
圖 2:新增專案。
題外話:在架構(F)沒看到.NET Framework 4.7.2,可以參考下面文件安裝
[Visual Studio] 如何為 Visual Studio 2017 增加 .NET Framework 4.7.2 開發套件
https://devmanna.blogspot.com/2018/05/visual-studio-2017-install-net-framework-4.7.2-sdk.html
從Visual Studio 2017的「網站(S)」選單,選取「加入新項目(W)」項目,新增一個ASP.NET Web Form (ASPX)網頁,請參考下圖所示:
圖 3:新增一個ASP.NET Web Form 網頁(ASPX)。
在「加入新項目(W)」對話盒中,選取「Web 表單」,設定名稱「GetRemoteData.aspx」,然後按下「新增」按鈕,新增一個網頁,請參考下圖所示:
圖 4:新增一個ASPX網頁。
點「設計」,雙擊游標處那邊的畫面空白處,進入程式設計視窗,Visual Studio 會自動產生一個Page_Load方法,刪除所有的HTML標籤,在其中加入以下程式碼:
圖 5:新增方法。
<%@ Page Language = "C#" %> <script runat = "server"> protected void Page_Load( object sender , EventArgs e ) { Response.ContentType = "application/json"; var term = Request.Params[ "term" ]; string[ ] data = { "Job" , "Japan" , "Korea", "Hong Kong" , "China" , "Singapore" , "Vietnam" }; var results = ( from d in data where d.ToUpper( ).StartsWith( term.ToUpper( ) ) select d ).ToList( ); System.Web.Script.Serialization.JavaScriptSerializer ser = new System.Web.Script.Serialization.JavaScriptSerializer( ); Response.Write( ser.Serialize( results ) ); } </script>
被廣泛的應用於WEB應用開發的JSON交換資料格式,範例中利用Response物件將ContentType 設定為「application/json」表示要送回JSON格式資料,然後將符合查詢條件的資料(即文字字串是以某個字母開頭的),利用JavaScriptSerializer 物件序列化成JSON格式回傳。
從「方案總管」視窗,選取「GetRemoteData.aspx」,按滑鼠右鍵,從快捷選單中選取「在瀏覽器中檢視(內部Web瀏覽器)(B)」選項,執行網頁,以查詢字串輸入查詢關鍵字,將J開頭的所有字串回傳:
http://localhost:55738/GetRemoteData.aspx?term=J
執行結果參考如下:
下圖是將「S」開頭的所有字串回傳之執行結果:
※注意:選這個先前的版本來用,會有一些像是URL及埠號無法修改的情形。
下載「jQuery」3.4.1版函式庫
用戶端的程式需要使用到jQuery與jQuery UI函式庫,在Visual Studio 2017開發工具中,可以使用Nuget套件管理員下載它們。在「方案總管」視窗選取專案名稱。從Visual Studio 2017開發工具「工具(T)」-「NuGet套件管理員(N)」-「套件管理器主控台(O)」開啟「套件管理器主控台」視窗,然後在提示字元中輸入install-package指令,並使用「-version」指定安裝jQuery 3.4.1版本:
[ads2]
圖 6:使用Nuget套件管理員。
Install-Package jQuery -Version 3.4.1
如果不知道版本,可以輸入Install-Package jQuery,應該可以找到jQuery最新的版本。
得到的執行結果如下圖所示:
圖 7:下載「jQuery」3.4.1版函式庫。
下載「jQuery UI (Combined Library)」1.12.1版函式庫
下一步,使用Nuget套件管理員下載「jQuery UI (Combined Library)」1.12.1版函式庫。在「方案總管」視窗選取專案名稱。從Visual Studio 2017開發工具「工具(T)」-「NuGet套件管理員(N)」-「套件管理器主控台(O)」開啟「套件管理器主控台」視窗,然後在提示字元中輸入install-package指令,並使用「-version」指定安裝jQuery UI (Combined Library) 1.12.1版本或是不指定版本:
Install-Package jQuery.UI.Combined -Version 1.12.1
Install-Package jQuery.UI.Combined
得到的執行結果如下圖所示:
[ads2]
圖 8:下載「jQuery UI (Combined Library)」1.12.1版函式庫。
使用GET方法回傳JSON格式資料
用戶端的程式可以是Web Form(ASPX)網頁或HTML。我們就以HTML為例子。在Visual Studio 2017「專案」-「加入新項目」對話盒中,選取「HTML 頁面」,設定名稱,然後按下「新增」按鈕,新增一個網頁,網頁程式碼參考如下:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <link href="Content/themes/base/all.css" rel="stylesheet" /> </head> <body> <input type="text" name="myInput" id="myInput" /> <script src="Scripts/jquery-3.4.1.js"></script> <script src="Scripts/jquery-ui-1.12.1.js"></script> <script> $(function () { $("#myInput").autocomplete({ source: function (request, callback) { var data = { term: request.term }; $.ajax({ url: "GetRemoteData.aspx", type: "GET", data: data, async: false, complete: function (xhr, result) { var lists = JSON.parse(xhr.responseText); callback(lists); } }); } }) }); </script> </body> </html>
網頁的設計重點如下:
- 在<head>標籤之中,加入以下引用jQuery UI 樣式表語法。
- 在<body>的<div>標籤之中加入一個HTML – input標籤。
- 在</body>標籤之上引用jQuery以及jQuery UI函式庫。
- 加入<script>區塊,於jQuery的ready事件撰寫程式碼,叫用ajax方法取回資料,使用HTTP GET方法呼叫ASPX檔案,將執行結果指定給jQuery UI Autocomplete Widget的source屬性。在source的callback函式中,可以利用request.term取得文字方塊中,使用者輸入的關鍵字。
現在可以來測試網頁的執行結果了。從「方案總管」視窗- 切換「解決方案與資料夾」下的HTML網頁,按CTRL+F5執行網頁,執行結果參考如下:
圖 9:自動完成功能。
第二種是Web Application Project(WAP)的方式
啟動Visual Studio 2017開發環境,從 Visual Studio 2017的主選單點選「檔案(F)」-「新增(N)」-「新增專案(P)」選項,接著會開啟「新增專案」對話窗,選取「Visual C#」 – 「Web」分類中,選取 「ASP.NET Web 應用程式(.NET Framework)」,設定名稱為autodemo1,位置自己選,方案名稱為autodemo1,請參考下圖所示:
圖 10:新增專案。
在「新增ASP.NET Web應用程式」對話盒中選取「空白」,勾選下方的「Web Form」項目,然後按下「確定」按鈕建立專案。
圖 11:新增應用程式。
從Visual Studio 2017的「專案(P)」選單,選取「加入新項目(W)」項目,新增一個ASP.NET Web Form (ASPX)網頁,請參考下圖所示:
圖 12:新增一個ASP.NET Web Form 網頁(ASPX)。
在「加入新項目(W)」對話盒中,選取「Web 表單」,設定名稱「GetRemoteData.aspx」,然後按下「新增」按鈕,新增一個網頁,請參考下圖所示:
圖 13:新增一個ASPX網頁。
注意這裡所開啟的GetRemoteData.aspx,會另外產生GetRemoteData.aspx.cs及其他相關檔案,為了避免不易操作,可以直接複製上面的範例程式到這個專案中,方便測試應用。
從「方案總管」視窗,選取「GetRemoteData.aspx」,按滑鼠右鍵,從快捷選單中選取「在瀏覽器中檢視(內部Web瀏覽器)(B)」選項,執行網頁,以查詢字串輸入查詢關鍵字,將J開頭的所有字串回傳:
http://localhost:61132/GetRemoteData.aspx?term=J
※如果不喜歡61132這個埠號,可以在「方案總管」視窗,選取「autodemo1」,按滑鼠右鍵選擇「屬性」,進行下一個步驟。
圖 14:屬性。
選取「Web」,在「專案 URL(J)」欄位從5000—65535輸入想要的埠號,彈出視窗按「是(Y)」就完成了。
圖 15:專案URL。
圖 15:建立虛擬目錄。
如果你選錯了埠號,就會出現這個視窗~
圖 16:屬性頁變更。
執行結果參考如下:
下圖是將「S」開頭的所有字串回傳之執行結果:
ASP.NET Web Service(ASMX)
接著,讓我們使用ASP.NET Web Service(ASMX)當做伺服端程式。延續前面的專案,加入一個ASP.NET Web Service(ASMX)。從Visual Studio 2017開發工具-「方案總管」視窗- 專案名稱上方按滑鼠右鍵,從快捷選單選擇「加入」- 「加入新項目(W)」,開啟「加入新項目」對話盒,從右上方文字方塊輸入「asmx」搜尋,選取「Web 服務 (ASMX)」,設定名稱為「WebService.asmx」,清除勾選右下方的「將程式碼置於個別檔案中(P)」,然後按下「新增(A)」按鈕,建立新服務,請參考下圖所示:
[ads2]
圖 17:加入ASP.NET Web Service(ASMX)。
修改工具產生的程式碼,將類別上方 [System.Web.Script.Services.ScriptService] 這行程式的註解拿掉,以開放透過ASP.NET AJAX方式叫用,再撰寫一個GetData方法,上方標示「WebMethod」Attribute,開放外部程式做呼叫,GetData方法會根據傳入的term關鍵字,篩選回傳符合條件的資料(以某個字開頭的字串):
<%@ WebService Language="C#" Class="WebService" %> using System; using System.Web; using System.Web.Services; using System.Web.Services.Protocols; using System.Linq; [WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] // 若要允許使用 ASP.NET AJAX 從指令碼呼叫此 Web 服務,請取消註解下列一行。 [System.Web.Script.Services.ScriptService] public class WebService : System.Web.Services.WebService { [WebMethod] public string[ ] GetData( string term ) { string[ ] data = { "Microsoft" , "apple" , "Linux" , "Cisco" , "Oracle" , "Sun" , "Misc" }; var result = ( from d in data where d.ToUpper( ).StartsWith( term.ToUpper( ) ) select d ).ToArray( ); return result; } }
你不需要在程式中指定要回傳JSON或XML格式的資料,Web Service會自動根據需求決定。測試一下服務是否能正常執行。從「方案總管」視窗- 選取WebService.asmx檔案,按CTRL+F5執行,執行結果參考如下,你將看到一個Web服務測試頁面,點選瀏覽器上的「GetData」超連結:
圖 18:Web服務測試頁面。
進入Web服務測試畫面,輸入term為「J」,按下「叫用」按鈕,請參考下圖所示:
圖 19:叫用服務。
得到的執行結果如下圖所示,資料預設以XML方式回傳:
圖 20:取回XML格式資料
使用POST方法回傳 JSON格式資料
若想要Web服務(ASMX)回傳 JSON格式資料,需要以POST方式呼叫服務,並設定contentType為「”application/json; charset=utf-8″」,term參數要序列化成為json格式傳遞,程式參考如下:
[ads2]
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <link href="Content/themes/base/all.css" rel="stylesheet" /> </head> <body> <input type="text" name="myInput" id="myInput" /> <script src="Scripts/jquery-3.4.1.js"></script> <script src="Scripts/jquery-ui-1.12.1.js"></script> <script> $(function () { $("#myInput").autocomplete({ source: function (request, callback) { var data = { term: request.term }; $.ajax({ type: "POST", contentType: "application/json; charset=utf-8", url: "WebService.asmx/GetData", dataType: "json", data: JSON.stringify(data), //必需要序列化為json async: false, success: function (data) { console.log(data); callback(data.d); } }); } }) }); </script> </body> </html>
使用POST方法回傳 XML格式資料
若想要Web服務(ASMX)回傳 XML格式資料,則不用設定contentType,資料也不需序列化為JSON格式,取回XML格式的資料之後,再透過jQuery解析XML文件內容,程式參考如下:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <link href="Content/themes/base/all.css" rel="stylesheet" /> </head> <body> <input type="text" name="myInput" id="myInput" /> <script src="Scripts/jquery-3.4.1.js"></script> <script src="Scripts/jquery-ui-1.12.1.js"></script> <script> $(function () { $("#myInput").autocomplete({ source: function (request, callback) { var data = { term: request.term }; $.ajax({ url: "WebService.asmx/GetData", type: "POST", data: data, async: false, success: function (xml) { console.log(xml); var lists = []; $(xml).find("string").each(function () { lists.push($(this).text()); }); callback(lists); } }); } }) }); </script> </body> </html>
使用GET方法回傳 XML格式資料
預設為了安全性考量,Web服務並不允許使用HTTP GET方式呼叫,若需要使用GET方式叫用服務,則需要在網站根目錄下的Web.config檔案之中,加入以下設定,以啟用HttpGET:
<?xml version="1.0" encoding="utf-8"?> <!-- 如需如何設定 ASP.NET 應用程式的詳細資訊,請前往 https://go.microsoft.com/fwlink/?LinkId=169433 --> <configuration> <system.web> <compilation debug="true" targetFramework="4.7.2"/> <httpRuntime targetFramework="4.7.2"/> <webServices> <protocols> <add name="HttpSoap"/> <add name="HttpPost"/> <add name="HttpGet"/> </protocols> </webServices> </system.web> <system.codedom> <compilers> <compiler language="c#;cs;csharp" extension=".cs" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:default /nowarn:1659;1699;1701"/> <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:default /nowarn:41008 /define:_MYTYPE="Web" /optionInfer+"/> </compilers> </system.codedom> </configuration>
接著就可以在網頁之中使用HTTP GET來叫用服務:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title></title> <link href="Content/themes/base/all.css" rel="stylesheet" /> </head> <body> <input type="text" name="myInput" id="myInput" /> <script src="Scripts/jquery-3.4.1.js"></script> <script src="Scripts/jquery-ui-1.12.1.js"></script> <script> $(function () { $("#myInput").autocomplete({ source: function (request, callback) { var data = { term: request.term }; $.ajax({ url: "WebService.asmx/GetData", type: "get", data: data, async: false, success: function (xml) { console.log(xml); var lists = []; $(xml).find("string").each(function () { lists.push($(this).text()); }); callback(lists); } }); } }) }); </script> </body> </html>
小結
下次有機會再分享如何叫用WCF服務、如何利用Web API和MVC的Action Method來回傳符合篩選條件的資料。