Matthew Dresser
Matthew Dresser

Reputation: 11442

jQuery UI Re-populate Autocomplete textbox with ashx handler

Apologies for posting the ten billionth jQuery autocomplete question...

I'm having trouble with a jQuery UI autocomplete textbox. I'm unsure if I'm doing the right thing client-side to re-populate the autocomplete data source following keystrokes.

The javascript in my aspx page is as follows:

$(function() {
    $("#<%=txtAuthorityName.ClientID%>").autocomplete({
        minLength: 2,
        delay: 0,
        dataType: "json",
        search: function(data) {
            $.getJSON("AuthoritySearchHandler.ashx?SearchTerms=" + $("#<%=txtAuthorityName.ClientID%>").val() + "&AuthorityType=" + $("#<%=ddlSector.ClientID%>").val(), function(data) {
                $("#<%=txtAuthorityName.ClientID%>").autocomplete("option", "source", data);
            })
        }
    });
});

and the code in my ashx handler is as follows:

    public void ProcessRequest(HttpContext context)
    {
        string searchTerms = context.Request["SearchTerms"] ?? string.Empty;
        string authorityType = context.Request["AuthorityType"];
        int authorityTypeId = 0;
        string json = "";
        if (int.TryParse(authorityType, out authorityTypeId) && authorityTypeId > 0 && searchTerms.Length > 0)
        {
            JavaScriptSerializer serializer = new JavaScriptSerializer();
            var authorities = from a in BusinessLayer.SearchAuthorities(authorityTypeId, searchTerms)
                              select a.Name;
            json = serializer.Serialize(authorities);
        }
        context.Response.ContentType = "application/json";
        context.Response.Write(json);
        context.Response.End();
    }

I'm fairly sure the ashx handler is doing what it should (I've inspected the HTTP responses using fiddler to be sure). I'm getting the error "Microsoft JScript runtime error: Object expected"?

Upvotes: 1

Views: 4792

Answers (1)

lsuarez
lsuarez

Reputation: 4992

Not to totally throw off the direction you were going with this, but your handler may be better implemented and consumed as a WebMethod (i.e. either using a web service if you reuse the result generation method on multiple pages or as a page method on a single page if it's only used there).

A complete how-to for web services is here: http://encosia.com/2008/03/27/using-jquery-to-consume-aspnet-json-web-services/

To consume the exact same service as a page method, check out: http://encosia.com/2008/05/29/using-jquery-to-directly-call-aspnet-ajax-page-methods/

I have used and abused those articles several times.

You could frame your service or page method (declare this function static if you go with page method) as follows:

[WebMethod]
public string[] GetSearchResults(int authorityTypeId, string searchTerms)
{
    if (authorityTypeId > 0 && searchTerms != string.Empty)
    {
        var authorities = from a in BusinessLayer.SearchAuthorities(authorityTypeId, searchTerms)
                          select a.Name;
        return authorities.ToArray();
    }
    else
    {
        return null;
    }
}

You can bind the data source update to the search event as follows:

$(function() {
    $("#<%=txtAuthorityName.ClientID%>").autocomplete({
        minLength: 2,
        delay: 0,
        dataType: "json",
        search: function(e, ui) {
            var $input = this;
            $.ajax({
                type: "POST",
                contentType: "application/json; charset=utf-8",
                url: "/Path/To/Service/Or/page.aspx/GetSearchResults",
                data: "{authorityTypeId:"+ $("#<%=ddlSector.ClientID%>").val() + ",searchTerms:'" + $("#<%=txtAuthorityName.ClientID%>").val() + "'}",
                dataType: "json",
                success: function (result) {
                    $input.autocomplete("option", "source", result.d);
                }
            });
        }
    });
});

As an alternative to manually building the data member's JSON string for your $.ajax() call, you could instead build a data object and have the browser's JSON object stringify for you.

var data = {};
data.authorityTypeId = parseInt($("#<%=ddlSector.ClientID%>").val());
data.searchTerms = $("#<%=txtAuthorityName.ClientID%>").val();

$.ajax({
    ...    

    data: JSON.stringify(data)    
});

Keep in mind that support for native JSON objects in IE only began as recently as IE8 so you'd have to include a script to build it for older browsers like IE7.

I haven't used AutoComplete's search event binding, but I have bound the data source on page load through asynch postback so page rendering isn't blocked by downloading a database of over a thousand searchable names. That being said, I'm not certain what behavior would be produced binding data source updates to that event. My first instinct would be binding the data once during $(document).ready() to get all names and letting the autocomplete object do the filtration for you.

Upvotes: 2

Related Questions