Implementing the AJAXControlToolkit AutoCompleteExtender inside SharePoint

<Foreword>For those looking for help integrating the AJAXControlToolkit with SharePoint check out this post: Integrating ASP.NET AJAX with SharePoint</Foreword>

I’ve never been one to use JavaScript that much in my web development, partially because I haven’t had much training with it and partially because I usually work on heavy server side web applications.  My current work project was well suited for some of the AJAXControlToolkit controls so I’ve been trying out other controls in the toolkit to see what uses they may have.  Last week I ran into a difficult client request that I didn’t have an efficient solution for in my first few passes.  Here’s the back story.

The client has 500+ stores that they operate and part of the web application I’m designing sends messages between those stores.  The user will select various criteria for which stores are included: zone, district, state, etc.  One of the selections happens to be a custom store group code.  The number of store group codes currently used is well above 8000.  Obviously making the end user scroll through a list of 8000+ options is not ideal.  After attempting to implement a quick proof of concept of how bad performance was the web page chugged after every action.  The page size alone was over 1 MB and response time was going on 15-30 seconds or more.  What I wanted to present was something akin to a search engine (http://www.bing.com as an example) suggestion box that gives the user suggestions as they type.

AutoCompleteExtender3

With this type of solution I could have the user filter the available options to less than 600 with just 1 letter entered and less than 50 with 2 letters entered.  Not only would this be more manageable to search through, but it would also save posting all of that extraneous data into the web page file thereby reducing the page size considerably.  Eventually I ran across the AutoCompleteExtender from the AJAXControlToolkit.  The way this control extender works is that you wire up a target control (textbox) and a web service that you will call into to get your results.  Below is part of the code needed to get this working.  I included a TextBoxWatermarkExtender as well to give a hint to the user.

TextBox txt = new TextBox();

txt.ID = "txtStoreGroupList";

txt.Width = Unit.Percentage(100);

table.Rows[rowNum].Cells[3].Controls.Add(txt);


table.Rows[rowNum].Cells[3].Controls.Add(new LiteralControl("Type at least 2 characters of store group code"));


// watermark extender gives directions on adding store groups

AjaxControlToolkit.TextBoxWatermarkExtender twe = new AjaxControlToolkit.TextBoxWatermarkExtender();

twe.ID = "tweStoreGroupList";

twe.TargetControlID = "txtStoreGroupList";

twe.WatermarkText = "Begin typing store group code...";

table.Rows[rowNum].Cells[3].Controls.Add(twe);


// autocomplete extender enables lookup of store groups without loading all 8000+ onto page

AjaxControlToolkit.AutoCompleteExtender ace = new AjaxControlToolkit.AutoCompleteExtender();

ace.ID = "aceStoreGroupList";

ace.ServiceMethod = "GetStoreGroupCompletionList";

ace.ServicePath = "/_layouts/autocompleteservice.asmx";

ace.TargetControlID = "txtStoreGroupList";

ace.MinimumPrefixLength = 2;

ace.CompletionSetCount = 50;

ace.CompletionInterval = 300;

ace.EnableCaching = true;

table.Rows[rowNum].Cells[3].Controls.Add(ace);

Looking at the implementation of the AutoCompleteExtender I require a “MinimumPrefixLength” of 2 and a “CompletionSetCount” of 50 so that the result set is manageable.  I have created a Web Service “autocompleteservice.asmx” with a web method “GetStoreGroupCompletionList” to return my suggestion short list.  This required a little bit of trickery to get working, so note the web service and web method decoration attributes.

[WebService(Namespace = "Your namespace goes here")]

[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]

[System.Web.Script.Services.ScriptService]

public class AutoCompleteService : System.Web.Services.WebService

{

    static string _connectionstring = null;

    static DataTable dt = null;


    public AutoCompleteService()

    {


    }


    [System.Web.Services.WebMethod]

    [System.Web.Script.Services.ScriptMethod]

    public string[] GetStoreGroupCompletionList(string prefixText, int count)

    {

        List<string> results = new List<string>();


        // if datatable for store group data is empty, skip this step

        if (dt == null )

        {

            // CALL INTO DATABASE FOR RESULTS REMOVED


        }


        DataRow[] rows = dt.Select("Group_Code LIKE '" + prefixText + "%'");


        for (int i = 0; i < rows.Length  && i < count; i++)

        {

            results.Add(rows[i]["FormattedDescription"].ToString());

        }


        return results.ToArray();

    }

}

Be sure to include the “[System.Web.Script.Services.ScriptService]” attribute for the web service and the “[System.Web.Script.Services.ScriptMethod]” on the web method as they are not typical inclusions (thanks to this post for leading me in the right direction).  Essentially what they do is allow for the AJAX (any JavaScript really) to call this web service and web method.  Without them you will get something like a giant list of “undefined” values returned.  Now we simply need to publish this web service to a location that SharePoint can reach.  I chose the “/_layouts/” folder for convenience sake.  You could easily publish it to a different location or server that you have access to if needed.

What we end up with is a very nice and easy to use textbox with suggestions that improves performance, improves the user experience, and required minimal coding to complete.

AutoCompleteExtender1

AutoCompleteExtender2

As always please leave any feedback if you liked/disliked this example, have suggestions, etc.  Feel free to “borrow” my code snippets but please include references to the source material here if you do.

-Frog Out