2012-06-22

[ASP.NET]將jQuery autocomplete包成UserControl

jQuery的Autocomplete Plugin實在是個很方便的工具,個人在開發Web時很常用到它,例如用在查詢廠商統編、身分證之類很長的文數字時,實在不太可能完全記住它的全貌,這時就非常適合用Autocomplete功能來幫你過濾資料出來~

當然,要注意的是!當你輸入一個字就等於對DB過濾查詢一次,對DB的Loading是有一定的負擔,請務必考量清楚再使用它!

一個簡單不複雜的Web網站,大都屬於同一個性質的內容,例如它如果是一個處理訂單的,那[查詢訂購單號]一定會出現在多個網頁上,如果剛好想把它做成有Autocomplete功能,那就建議可以包成UserControl,以方便重覆使用。

以下就簡單例出一個擁有Autocomplete功能的UserControl做法:

新增一個UserControl網頁,其內容可參考如下:
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="Auto.ascx.cs" Inherits="UserControl_Auto" %>

<script type="text/javascript" language="javascript" src="jquery.autocomplete.js" />

<script language="javascript" type="text/javascript">

    // 設置請求完畢後再調用AutoComplete function
    Sys.WebForms.PageRequestManager.getInstance().add_endRequest(AutoComplete);

    // AutoComplete主要function
    function AutoComplete() 
    {
        $("#txtName").autocomplete("AutoDB.ashx",
        {
            // AutoComplete的屬性
            minChars: 1,
            matchSubset: 1,
            cacheLength: 1,
            autoFill: false,
            maxItemsToShow: 10,
            width: 300,
            mappingBy: "full"
        });        
    }
    
</script>

<table>
    <tr>
        <td>
            <asp:TextBox ID="txtName" runat="server" AutoCompleteType="Disabled" />
        </td>
    </tr>
</table>
Autocomplete的屬性,其中mappingBy: "full"個人建議一定要加,如此在查詢中文時比較不會有問題。其他參數的意思,都在jQuery Autocomplete Plugin Demo上能找到。TextBox屬性部份也建議要加AutoCompleteType="Disabled",它能避免掉元件本身記下的歷史記錄,以防跟Autocomplete相衝。

再來就是處理DB資料的過濾了,這例子是透過泛型處理函式AutoDB.ashx來使用:
public void ProcessRequest(HttpContext context)
{
     StringBuilder sResult = new StringBuilder();

     // 取得輸入的字
     string strRequest = context.Request.QueryString["q"];
 
     DataTable NewTable = GetAutocompleteName(strRequest);

     foreach (DataRow NewRow in NewTable.Rows)
     {
        sResult.Append(NewRow["Name"].ToString()).Append("\n");
     }
 
     context.Response.ContentType = "text/plain";
     context.Response.Write(sResult.ToString());
}
Autocomplete接收的參數名稱固定都是q參數。然後我再將查到的Name以\n跳行組合起來再回傳。

之後在aspx網頁上就能加入UserControl並使用它了,要注意的事!網頁記得要引用jQuery.js,這個例子我是使用v1.3.2的jQuery.js:
<%@ Page Language="C#" AutoEventWireup="true"
 ValidateRequest="false" CodeFile="Test.aspx.cs" Inherits="Test" %>

<!--先在最前面引用jQuery和UserControl-->
<%@ Register Src="Auto.ascx" TagName="Auto" TagPrefix="uc1" %>
<script language="javascript" src="jquery-1_3_2.js" />
...

<!--使用UserControl-->
<body>
    ...
    <uc1:AutoNAME ID="SearchNAMEText" runat="server" />
    ...
</body>
...

如此,一個擁有Autocomplete的UserControl就完成啦~


2012/12/24補充:
如果做完AutoComplete,而想馬上透過後端去查出其他資訊同步顯示在畫面(例如AutoComplete查詢出UserID就順便帶出姓名、電話等資訊),那必須先暫停一下再做後端的查詢,要等AutoComplete執行完了才開始執行查詢的事件。如果不暫停一下,查詢事件會跟AutoComplete事件互相重疊,導致不會執行到,實作方式如下:

後端事件:
//將UserControl1加上前端Onchange()事件
<uc1:AutoNAME ID="SearchNAMEText" runat="server" onchange="Onchange();"/>

//真正處理的事件
protected void Button1_Click(object sender, EventArgs e)
{
    ...
}

前端事件:
//暫停0.5秒後再呼叫後端的按鈕事件來處理
function Onchange() {
    setTimeout("OnClickChange();", 500);
}

function OnClickChange() {
    $("#<%=Button1.ClientID %>").click();
}

3 則留言:

  1. 不好意思 想請問一下...
    若今天我是將自動完成 這個功能
    做在類似地址欄位 該如何去做?
    因為我碰到 autopostback 之後 js 失效的問題

    我做了

    一個郵遞區號欄位
    一個縣市下拉 autopostback
    一個區域下拉 autopostback
    一個地址欄位

    外面有一層updpanel 包住

    在ASCX中我設定
    縣市 有值
    區域 有值 做一個AJAX去取街道
    並放入 地址欄位
    但就在 autopostback 的時候 在
    ASCX上寫的JS 卻沒觸發
    看網路上有人說 因為有包住 updpanel
    的關係 所以 ASCX 內寫的JS在 autopostback
    消失了 有人是說要註冊JS(註冊說真的我不太會)

    不知道有沒有其他方法可以解決這個問題...
    不知大大可否提供點意見






    回覆刪除
    回覆
    1. 建議在 ASCX 的 Javascript 加上 jQuery 初始 function,裡面放用 AJAX 取街道的 code,如此當網頁每次PostBack後,在jQuery準備完成就能執行。

      EX:
      // jQuery 初始 function
      $(function() {
       if (縣市 != "" && 區域 != ""){
        // AJAX 取街道的 code
       }
      });

      刪除
  2. 作者已經移除這則留言。

    回覆刪除