Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery Autocomplete and ASP.NET

I searched all over this site and the web for a good and simple example of autocomplete using jQuery and ASP.NET. I wanted to expose the data used by autocomplete with a webservice (and will probably do that next). In the meantime, I got this working, but it seems a little hacky...

In my page I have a text box:

<input id="txtSearch" type="text" />

I am using jQuery autocomplete, set up per their example:

<link rel="stylesheet" href="js/jquery.autocomplete.css" type="text/css" />
<script type="text/javascript" src="js/jquery.bgiframe.js"></script>
<script type="text/javascript" src="js/jquery.dimensions.pack.js"></script>
<script type="text/javascript" src="js/jquery.autocomplete.js"></script>

Here is where it starts to get hacky... I call a page instead of a webservice:

  <script type="text/javascript">
    $(document).ready(function(){
        $("#txtSearch").autocomplete('autocompletetagdata.aspx');
    });      
  </script>

In the page I stripped out ALL of the html and just have this (otherwise, various HTML bits show up in the autocomplete dropdown):

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="autocompletetagdata.aspx.cs" Inherits="autocompletetagdata" %>

And in my autocompletetagdata.aspx, I am using SubSonic to query, format and return data from the database (one data item per line):

protected void Page_Load(object sender, EventArgs e)
{
    // Note the query strings passed by jquery autocomplete:
    //QueryString: {q=a&limit=150&timestamp=1227198175320}

    LookupTagCollection tags = Select.AllColumnsFrom<LookupTag>()
        .Top(Request.QueryString["limit"])
        .Where(LookupTag.Columns.TagDescription).Like(Request.QueryString["q"] + "%")
        .OrderAsc(LookupTag.Columns.TagDescription)
        .ExecuteAsCollection<LookupTagCollection>();

    StringBuilder sb = new StringBuilder();

    foreach (LookupTag tag in tags)
    {
        sb.Append(tag.TagDescription).Append("\n");
    }

    Response.Write(sb.ToString());
}

If you don't do a LIKE query, then it returns everything that contains a match for the character(s) you type -- e.g., typing "a" will include "Ask" and "Answer" as well as "March" and "Mega." I just wanted it to do a starts with match.

Anyway, it works and it's pretty easy to set up, but is there a better way?

like image 933
djuth Avatar asked Nov 20 '08 16:11

djuth


3 Answers

I just recently implemented autocomplete, and it looks fairly similar. I'm using an ashx (Generic Handler) instead of the aspx, but it's basically the same code in the code behind.

Using the ashx, it'll look something like this:

<script type="text/javascript">
  $(document).ready(function(){
      $("#txtSearch").autocomplete('autocompletetagdata.ashx');
  });      
</script>

[WebService(Namespace = "http://www.yoursite.com/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class AutocompleteTagData : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        // Note the query strings passed by jquery autocomplete:
        //QueryString: {q=a&limit=150&timestamp=1227198175320}

        LookupTagCollection tags = Select.AllColumnsFrom<LookupTag>()
            .Top(context.Request.QueryString["limit"])
            .Where(LookupTag.Columns.TagDescription).Like(context.Request.QueryString["q"] + "%")
            .OrderAsc(LookupTag.Columns.TagDescription)
            .ExecuteAsCollection<LookupTagCollection>();

        foreach (LookupTag tag in tags)
        {
            context.Response.Write(tag.TagDescription + Environment.NewLine);
        }
    }

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }
}
like image 172
bdukes Avatar answered Oct 12 '22 22:10

bdukes


I just posted this on another question, but you can override the parse function on the jQuery autocomplete plug-in to make it support any output.

Example:

    $("#<%= TextBox1.ClientID %>").autocomplete("/Demo/WebSvc.asmx/SuggestCustomers", {
        parse: function(data) {
            var parsed = [];

            $(data).find("string").each(function() {
                parsed[parsed.length] = {
                    data: [$(this).text()],
                    value: $(this).text(),
                    result: [$(this).text()]
                };
            });
            return parsed;
        },
        dataType: "xml"
    });

All this expects is a string array to XML... Very easy to do... If your using SubSonic, you should check out the RESTHandler (It's a hidden GEM!!!), it supports basic queries on all your objects and can return JSON/XML. Here is an example query using it...

/Demo/services/Customers/list.xml?CustomerName=JOHN

If you change list.xml to list.json it will change the results to JSON. The request above will return the a strongly typed "Customer" entity. You can change the parameter to support LIKE, NOT LIKE, etc... Very powerful and all the plumbing is arleady done...

Here is a video on it: http://subsonicproject.com/tips-and-tricks/webcast-using-subsonic-s-rest-handler/

like image 35
Zachary Avatar answered Oct 12 '22 22:10

Zachary


The web service or a WCF service will give you the potential for a better interface. Both can also be set up to do Json serialization.

Since I'm taking a WCF class as I write (I'm on a break, really!), I'll sketch the WCF method.

[OperationContract]
[WebInvoke(RequestFormat=WebMessageFormat.Json,
           ResponseFormat=WebMessageFormat.Json)]
public LookupTagCollection LookupTags( int limit, string q )
{
     return Select.AllColumnsFrom<LookupTag>()
                  .Top(limit)
                  .Where(LookupTag.Columns.TagDescription)
                  .Like(q+ "%")
                  .OrderAs(LookupTag.Columns.TagDescription)
                  .ExecuteAsCollection<LookupTagCollection>();    
}

LookupTagCollection needs to be Serializable.

like image 6
tvanfosson Avatar answered Oct 12 '22 22:10

tvanfosson