Aishwarya Shiva
Aishwarya Shiva

Reputation: 3406

Efficient way of using JQuery UI Autocomplete with ASP.NET

I am using JQuery UI Autocomplete with my ASP.NET-C# Website.

JavaScript:

$(function () {
        var availableTags = [
            <%=GetAvaliableTags() %>
        ];
        $("input.tag_list").autocomplete({
            source: availableTags
        });
    });

C# Function in code-behind:

public string GetAvaliableTags()
{
    var tags = new[] { "ActionScript", "Scheme" };
    return String.Join(",", tags.Select(x => String.Format("\"{0}\"", x)));
}

This is working fine. But I have a doubt that if I fetch the big amount of tags from database, it will load all those tags on page load at once, making it slow. The efficient way that came to my mind is to use Ajax. But I am not a Ajax programmer and know little about it. Can any one please tell me how to do it with Ajax efficiently? How to call GetAvailableTags on demand?

UPDATE

I tried like this:

 $(function () {
                var availableTags = [function () {
                    $.ajax({
                        type: "POST",
                        contentType: "application/json; charset=utf-8",
                        url: "CreateTopic.aspx/GetAvaliableTags",
                        data: "{ 'key' : '" + $("input.tag_list").val() + "'}",
                        dataType: "json",
                        async: true,
                        dataFilter: function (data) { return data; },
                        success: function (data) {if (result.hasOwnProperty("d")) {

                          $("input.tag_list").autocomplete({
                              source: result.d
                          });
                      }
                      else {
                          // No .d; so just use result
                          $("input.tag_list").autocomplete({
                              source: result
                          });
                    });
                }];
                $("input.tag_list").autocomplete({
                    source: availableTags
                });
            });

Web Method equivalent of GetAvailableTags()

[System.Web.Services.WebMethod]
public static string GetAvaliableTags(string key)
{
    var tags = new[] { "ActionScript", "Scheme" };
    return String.Join(",", tags.Select(x => String.Format("\"{0}\"", x)));
}

But the Ajax call is not being fired. What can be the reason?

Upvotes: 4

Views: 16960

Answers (3)

Saurabh Singh
Saurabh Singh

Reputation: 63

If you want real time update of options

    $(document).ready(function() {   
            $("textbox").autocomplete({
                source: function (request, response) {
                pageMethod.yourmethodname(request.term,onSuccess)
                function onSuccess(Responce){
                                  data = JSON.parse(Responce)
                                  response($.map(data.d, function (item) {
                                          return {
                                                 value: item
                                                  }
                                     }

    };

Upvotes: 0

sh1rts
sh1rts

Reputation: 1884

I've got a good solution I implemented in an intranet app; it uses the jQuery UI Autocomplete function with an HttpHandler, and only searches for customers beginning with whatever's in the input; it's also only triggered when there are 3 or more characters typed. This means you're never retrieving the entire table, just a subset of it.

Firstly the HttpHandler. I won't go into the data-retrieval nuts and bolts cos you can probably figure out that part yourself. SUffice to say it calls a stored procedure to return customers whose name starts with (whatever was sent to the Handler), and returns a JSON-serialized array of matches to the Autocomplete handler.

using Newtonsoft.Json;

namespace Invoicing.HttpHandlers
{
    [WebService(Namespace = "yournamespace/http-handlers/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    public class CustomerHandler : IHttpHandler
    {
        #region IHttpHandler Members

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }

        public void ProcessRequest(HttpContext context)
        {
          // your data-retrieval logic here
          // write json to context.Response
        }
    }

If you're not used to this approach I'll just quickly describe the JSON part.

Basically, I have a small wrapper-type object called "ResponseCustomer" because I only really need Customer ID and Name for the Autocomplete handler, not the complete Customer details: -

[Serializable]
public class ResponseCustomer
{
    public int ID;
    public string CustomerName;
}

IHttpHandler.ProcessRequest invokes my stored procedure, and transforms the results into an IList - this means the JSON returned is as lean as possible: -

    public void ProcessRequest(HttpContext context)
    {
        string json = string.Empty;

        // note the httpcontext.Request contains the search term
        if (!string.IsNullOrEmpty(context.Request["term"]))
        {
            string searchTerm = context.Request["term"];
            var customers = (data access component).CustomerSearch(searchTerm); // call Search stored proc

            if (customers.Count != 0)
            {
                var transformList = new List<ResponseCustomer>();

                for (int index = 0; index < customers.Count; index++)
                {
                    transformList.Add(new ResponseCustomer
                    {
                        ID = customers[index].ID,
                        CustomerName = customers[index].CustomerName
                    });
                }

                // call Newtonsoft.Json function to serialize list into JSON
                json = JsonConvert.SerializeObject(transformList);
            }

        }

        // write the JSON (or nothing) to the response
        context.Response.Write(json);
    }

So far so good ?

Make sure this HttpHandler is wired into web.config (note you will have to do this differently for IIS6 than for IIS 7+): -

      <system.web>

        <!-- Custom HTTP handlers (IIS 6.0) -->
        <httpHandlers>
          <add path="customerHandler.ashx" verb="*" type="(namespace).(handler name), (assembly name)" />

i.e.

      <add path="customerHandler.ashx" verb="*" type="MyProject.Handlers.CustomerHandler, MyProject" />

    and for IIS7: -


  <system.webServer>

    <handlers>
      <!-- Custom HTTP handlers (IIS7+) -->
      <add name="customerHandler" preCondition="integratedMode" verb="*" path="customerHandler.ashx" type="(namespace).(handler name), (assembly name)"" />

Finally wire in the client-side, as you already know: -

HTML: -

        <span>Customer</span>
        <span class="ui-widget" style="display:inline-block">
            <input id="txtCustomer" runat="server" clientidmode="Static" />
        </span>

JS: -

$(function ()
{
    $("#txtCustomer").autocomplete(
        {
            source: "customerHandler.ashx",
            // note minlength, triggers the Handler call only once 3 characters entered
            minLength: 3,
            select: function (event, ui)
            {
                if (ui.item)
                {
                    $("#txtCustomer").val(ui.item.CustomerName);
                    return false;
                }
            }
        })
        .data("autocomplete")._renderItem = function (ul, item)
        {
            // insert an item into the autocomplete dropdown (YMMV)
            return $("<li></li>")
                .data("item.autocomplete", item)
                .append("<a><table cellpadding='0' cellspacing='0' border='0' width='250px'><tr><td width='200' valign='top' align='left'>"
                + item.CustomerName + "</td><td width='50px' valign='top' align='left'>[ID "
                + item.ID + "]</td></tr></table></a>")
                .appendTo(ul);
        };
});

Let me know if this helps, I can email you the relevant source files if you want.

Upvotes: 0

Karl Anderson
Karl Anderson

Reputation: 34844

I would recommend using an ASP.NET AJAX Page Method on the server-side and have the jQuery .ajax() function call it to retrieve the data, like this:

Code-behind:

[WebMethod]
public static string GetAvailableTags()
{
    // Put logic here to return list of tags (i.e. load from database)
    var tags = new[] { "ActionScript", "Scheme" };
    return String.Join(",", tags.Select(x => String.Format("\"{0}\"", x)));
}

Markup:

$(document).ready(function() {
    $.ajax({
        type: "POST",
        url: "PageName.aspx/GetAvailableTags",
        data: "{}",
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        success: function(result) {
            if (result.hasOwnProperty("d")) {
                // The .d is part of the result so reference it
                //  to get to the actual JSON data of interest
                $("input.tag_list").autocomplete({
                    source: result.d
                });
            }
            else {
                // No .d; so just use result
                $("input.tag_list").autocomplete({
                    source: result
                });
            }
        }
    });
});

Note: You will need to change the name of PageName.aspx to the name of your .aspx page. Also, the .d syntax was an anti-XSS protection put in by Microsoft in the ASP.NET 3.5 release of ASP.NET AJAX; therefore the check to see if the .d property is there or not.

Upvotes: 7

Related Questions