Thursday, January 5, 2012

jQuery Autocomplete Via JSON in ASP

On a recent project, we needed to add autocomplete functionality to a few text fields. As I've noted before, in past lives, I would do this through jQuery-UI's autocomplete, with a stand-alone page that does nothing but echo the desired JSON string. Since I'm happy with jQuery's implementation, I decided that the best bet was to go ahead and replicate this functionality in ASP.Net. Turns out, it's pretty darn easy.

First, the change to the client-side/display code: In the code-front (with the HTML), nothing changes. In the Javascript onload function, one line needs to be added:
$("#txtRequestType").autocomplete({ 
   source: "json.aspx", delay: 100 
});
I always set the delay to 100ms because the default of 300ms feels aggravatingly slow to me.

Next, we construct the server-side JSON generation code. This is where I expected to encounter some hang-ups, as I wasn't even sure what type of ASP.Net project item to use to create a page that had only text/JSON content. I played with a few options before coming on a Stack Overflow question that made it trivial to create a text/JSON-only page. The key was to build the JSON string and then use the Response object to write the JSON string and then close it (writing nothing else):
protected void Page_Load(object sender, EventArgs e)
{
  string json = getJsonString();
  Response.Clear();
  Response.ContentType = "application/json; charset=utf-8";
  Response.Write(json);
  Response.End();
}
You could just build your JSON string in that function, but splitting it out to a separate function seems like the correct decision. Plus, it allowed maximum extensibility by using an optional source parameter to specify what should be used to build the JSON string, making this page a multi-purpose one:
protected string getJsonString()
{
   LandLordDataContext db = new DataContext();
   var Values = (from t in db.Table1
   orderby t.Field1
   select t.Field1).Distinct();

   if (Request["source"] == "Table1Field1")
   {
     Values = (from t in db.Table1
               orderby t.Field1
               select t.Field1).Distinct();
   }
   else if (Request["source"] == "Table2Field3")
   {
      Values = (from t in db.Table2
                orderby t.Field3
                select t.Field3).Distinct();
   }

   string strJson = "";
   string currValue = "";
   foreach (var Value in Values)
   {
      currValue = Value.ToString();
      if ((Request["term"] == null) || (currValue.ToLower().Contains(Request["term"].ToLower())))
      { strJson = strJson + ", \"" + currValue + "\""; }
   }
   if (strJson.Length > 2) strJson = strJson.Substring(2);

   string strResult = "[" + strJson + "]";
   return strResult;
}
The final thing worth noting here is that you have to do the filtering on the server-side. That might be counter-intuitive if you've otherwise used a javascript array to interface with jQuery's autocomplete (where it does the filtering automatically). That's where the processing around Request["term"] comes into play (inside the foreach of the final function).

Overall, this took only slightly longer to sort out and set up than an equivalent setup would have taken me on the LAMP stack. But going forward, it will be trivial to repeat in minutes.

2 comments:

  1. @Farmer Webster: Yes, that is true. Pastebin doesn't allow new content while their site is being overtaken by DDOS Cats. So I used Google Prettify instead.

    ReplyDelete