views:

27208

answers:

7

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?

+14  A: 

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;
        }
    }
}
bdukes
Did you have issues with permissions in IIS for the ashx file? I used this method and when I deploy the application to IIS 6, the browser can't access the ashx file.
Gromer
+3  A: 

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.

tvanfosson
Unfortunately, the Autocomplete widget doesn't expect JSON, it just wants text, each item on a new line. But for JSON stuff that looks nice. What URL would you use to access that?
bdukes
A: 

I'm doing something very different but using a Web Service instead of a HTTP Handler because I can take advantage of the HTTP GET Caching that I can easily do by attributes with web services.

Is there a way to do HTTP GET Output Caching based on parameters with a HTTP Handler also?

Thanks...

+5  A: 

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/

Zachary
This is the actual answer to handle XML with a name/value pairing. The marked answer above is only for the display text - you can't set/get a value pairing.
eduncan911
A: 

Look this simple jquery autocomplete implementation in ASP.net without JSON. http://aspnetnova.blogspot.com/2009/06/simple-jquery-ajax-server-side.html

A: 

hi

where can I get the js plugin file ? ?

thanks //// :)

haddar
http://bassistance.de/jquery-plugins/jquery-plugin-autocomplete/
teedyay
A: 

is it Possible to add an a tooltip for each item that shows up in the autocomplete ?

Raul
Welcome at StackOverflow. Please don't post a question as an answer. Use the _Ask Question_ button at the right top to ask a question. Use the _Your Answer_ field only to post answers on a question.
Espo