Using the AutoCompleteExtender AJAX control in Delphi for .NET

By: David Clegg

Abstract: Describes how to use the AutoCompleteExtender AJAX control to provide auto-complete textbox functionality in Delphi for .NET ASP.NET applications

    Introduction

With the introduction of the Microsoft ASP.NET 2.0 AJAX Extensions framework, and the corresponding Microsoft AJAX Control Toolkit, Microsoft has provided ASP.NET developers an easy way to incorporate AJAX functionality into their web applications. This article will show how to use the AutoCompleteExtender control from the AJAX Control Toolkit to provide auto-complete textbox functionality in Delphi for .NET ASP.NET applications. It will also show how to use the AJAX Extensions framework to make asynchronous server side callbacks, with the result of the call being available in client-side JavaScript.

    Configuring the Development Environment

    AJAX Extension Framework and Control Toolkit

The code in this article consumes classes from Microsoft ASP.NET 2.0 AJAX Extensions framework, and the Microsoft AJAX Control Toolkit.

You are given the option to install the ASP.NET 2.0 AJAX Extensions framework as part of the RAD Studio 2007 install process. If this hasn’t been installed already, the installer can be obtained from the RAD Studio 2007 installation DVD, or downloaded from the ASP.NET AJAX downloads page.

The Microsoft AJAX Control Toolkit is not included as part of the RAD Studio 2007 installer, so this will have to be downloaded from the ASP.NET AJAX downloads page.

Once the AJAX Control Toolkit has been installed, the controls can be installed into the RAD Studio 2007 IDE so they can be used with the ASP.NET designer. To do this, select Components->Installed .NET Components from the IDE main menu.

Hide image
Click to see full-sized image

On the .NET Components tab, enter ‘AJAX Controls’ in the Category textbox. Click the Select an Assembly button, navigate to the directory where the AJAX Control Toolkit was installed, and double-click on the AjaxControlToolkit.dll assembly. We should now have a new AJAX Controls Tool Palette category available to us which contains a plethora of AJAX enabled web controls.

Hide image
Click to see full-sized image

    Fiddler HTTP Debugger

Developing and debugging AJAX applications can be a frustrating experience at times. If there is a configuration or code error, it is common for AJAX calls to silently fail with no indication of what went wrong. In order to assist with this, we will use the Fiddler HTTP debugging proxy, which is freely downloadable from here.

Once Fiddler has been installed, it will enable us to monitor the HTTP communications between the browser and web server, including any HTTP errors which may be preventing our web application from behaving as we expect it to. Fiddler can be invoked directly from Internet Explorer. It can also be used with other web browsers such as Firefox, but these may require additional configuration to ensure all HTTP requests are routed through Fiddler.

    Firebug Firefox Plug-in

While Fiddler can be used to debug HTTP communications, it won’t help with debugging the JavaScript portions of AJAX web applications. If you are a Firefox user, you can take advantage of the excellent Firebug plug-in to assist with this. Firebug is freely downloadable from here. In addition to providing JavaScript and HTML debugging support, it will also provide the ability to monitor the HTTP communications. Although this functionality isn’t as feature rich as the HTTP debugging provided by Fiddler, it should still be sufficient to debug most AJAX communication issues.

    Creating the Application

    Creating an AJAX-Enabled Web Application

Once we have our development environment configured, we can create our first AJAX enabled web application. Select File->New->Other… from the IDE main menu. Expand the Delphi for .NET Projects node, and double-click on the AJAX-Enabled ASP.NET Web Application icon.

Hide image

When prompted for the project name, type AutoCompleteTest and click the OK button.

    Consuming the AutoCompleteExtender Control

The AJAX-Enabled ASP.NET Web Application template would have created a Default.aspx page which contains a ScriptManager and UpdatePanel control. For this application, we don’t need the UpdatePanel control, so select this in the ASP.NET designer, and press the Delete key.

As the AutoCompleteExtender control extends the functionality of the System.Web.UI.WebControls.TextBox control, we need to add a TextBox control to our web page. The AutoCompleteExtender control will be dropping down a list of available entries for the user to choose from, so we will disable the standard auto-complete functionality the TextBox control supports. To do this, set the TextBox.AutoCompleteType property to Disabled.

Hide image
Click to see full-sized image

Next we need to add an AutoCompleteExtender control to the web form, and associate it with the TextBox we’ve already added. This is done by setting the AutoCompleteExtender.TargetControlID property to the name of the TextBox.

Hide image

    Implementing the Server Method

There are two ways to provide a server-side method for our AutoCompleteExtender control to call. The first is to implement a web service method which it can call, and the second is to implement a method in the class implemented in the code behind file for our web page. This article will demonstrate both approaches.

    Implementing a Web Service Method

Right-click on the AutoCompleteTest.dll node in the Project Manager, and select Add New->Other…. Expand the Delphi for .NET Projects node, and select the New ASP.NET Files node. Double-click on the ASP.NET Web Service icon.

Hide image

Type AjaxMethods.asmx in the Name textbox, and click the OK button.

Open the AjaxMethods.pas file in the Code Editor, and add the following type declaration:-

type
  TStringArray = array of string;

This will be the type we return in the function call used to determine the list of items to show in the auto-complete dropdown.

In the interface section of the TAjaxMethods class, add a method with the following signature:-

[WebMethod]
function GetAutoCompleteList(prefixText: string; count: Integer): TStringArray;

The prefixText parameter indicates the text that the user has typed into the TextBox control, and the count parameter indicates the maximum number of elements to return in the string array.

While you can use any name you want for the method, it is important to use the exact parameter names and case as shown above, otherwise the AJAX Extensions Framework will be unable to resolve the parameters when making the web service call.

It is also possible to create an overloaded version of the above method which also passes a contextKey string parameter. If this parameter is passed, you will also need to set the ContextKey property of the AutoCompleteExtender control in your .aspx file. This provides a mechanism for each AutoCompleteExtender instance to signify context to the web service method implementation.

In the implementation section of the TAjaxMethods class, add the following implementation for the GetAutoCompleteList method:-

function TAjaxMethods.GetAutoCompleteList(prefixText: string; count: Integer): TStringArray;
var
  I: Integer;
begin
  SetLength(Result, Count);
  for I := 1 to Count do
    Result[I - 1] := prefixText + I.ToString;
end;

This implementation is for demonstration purposes only, and will simply return an array of strings, with the size determined by the count parameter, and each array item consisting of the specified prefix parameter with its array position appended to it.

Now that we have a server side method for the AutoCompleteExtender to call, we can configure it to call this method. Open up the .aspx file for the web page, and change the definition of the AutoCompleteExtender control to the following:-

<cc1:AutoCompleteExtender
id="AutoCompleteExtender1"
runat="server"
targetcontrolid="TextBox1"
servicemethod="GetAutoCompleteList"
servicepath="AjaxMethods.asmx"
MinimumPrefixLength="1" />

The important thing to note here is the definition of the servicemethod and servicepath attributes. These denote the name of the web service method, and location of the web service .asmx file respectively.

Debugging using Fiddler

Now it is time to run our application to see whether it works as expected. Select Run->Run from the IDE main menu to launch it in a web browser. Set focus to the TextBox, and start typing. As you will quickly discover, we have not quite finished the implementation yet, and no auto-complete dropdown will be shown. This provides the perfect opportunity to introduce how Fiddler can be used to determine what has gone wrong.

Fiddler can either be launched from its Start Menu program icon, or if you are using Internet Explorer there will be an option to launch it directly from there (in IE7 for example, there will be a Fiddler2 icon on the Command Bar).

NOTE: When using Fiddler to debug local web applications, it is important to remember that Internet Explorer 7 and the .NET Framework are hardcoded not to send requests for localhost through any proxies. And because Fiddler installs itself as a proxy, this means it won’t be able to intercept any such traffic. The easiest way to get around this is to refer to your local machine name in the URL instead of localhost.

Once Fiddler has launched, switch focus back to the web browser and type in the TextBox again. Now switch focus back to Fiddler, and you should see an entry in the Web Sessions list for a HTTP call to our web service method, which failed with a result of 500. Double-clicking on the entry will expand the information in the Session Inspector tab, and will allow us to see what went wrong. The top section shows the request, and the bottom section shows the response.

Hide image
Click to see full-sized image

By default the TextView tab will be shown in the response section, and that tells us exactly why the call failed. The title element of the returned HTML states that “Only Web services with a [ScriptService] attribute on the class definition can be called from script”.

NOTE: If you are using Firefox with the FireBug plug-in installed, the failed HTTP web service call would be shown in the Console tab. And by expanding this entry, you will be able to see the HTML response sent indicating the error.

Hide image
Click to see full-sized image

In order to expose web service methods which can be called by the AJAX Extensions Framework, we must decorate our web service classes with the ScriptServiceAttribute attribute. This attribute resides in the System.Web.Script.Services namespace. Here is the complete implementation for a valid web service implementation which our client side code can consume:

unit AjaxMethods;

interface

uses
  System.Collections, System.ComponentModel,
  System.Data, System.Diagnostics, System.Web,
  System.Web.Services, System.Web.Script.Services;

type
  TStringArray = array of string;

  [ScriptService]
  [WebService(Namespace = 'http://tempuri.org/')]
  [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
  TAjaxMethods = class(System.Web.Services.WebService)
  {$REGION 'Designer Managed Code'}
  strict private
    /// <summary>
    /// Required designer variable.
    /// </summary>
    components: IContainer;
    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    procedure InitializeComponent;
  {$ENDREGION}
  strict protected
    /// <summary>
    /// Clean up any resources being used.
    /// </summary>
    procedure Dispose(disposing: boolean); override;
  private
    { Private Declarations }
  public
    constructor Create;
    [WebMethod]
    function GetAutoCompleteList(prefixText: string; 
 count: Integer): TStringArray;
  end;

implementation

{$REGION 'Designer Managed Code'}
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
procedure TAjaxMethods.InitializeComponent;
begin

end;
{$ENDREGION}

constructor TAjaxMethods.Create;
begin
  inherited;
  //
  // Required for Designer support
  //
  InitializeComponent;
  //
  // TODO: Add any constructor code after InitializeComponent call
  //
end;

/// <summary>
/// Clean up any resources being used.
/// </summary>
procedure TAjaxMethods.Dispose(disposing: boolean);
begin
  if disposing and (components <> nil) then
    components.Dispose;
  inherited Dispose(disposing);
end;

function TAjaxMethods.GetAutoCompleteList(prefixText: string; 
  count: Integer): TStringArray;
var
  I: Integer;
begin
  SetLength(Result, Count);
  for I := 1 to Count do
    Result[I - 1] := prefixText + I.ToString;
end;

end.

Once we have changed our web service implementation to use the above code, we should be able to compile and run our application again, and have the auto-complete list drop down as expected. In addition, Fiddler will now show a HTTP response with a result code of 200, and the items to be shown in the list will be clearly visible in the TextView tab of the response section

Hide image
Click to see full-sized image

    Implementing a Page Method

As an alternative to using a web service to expose the server-side methods for the AutoCompleteExtender control to call, it is possible to implement a page method in the code-behind class for the page.

In order to demonstrate this, we will add additional TextBox and AutoCompleteExtender controls to our page, and will configure the AutoCompleteExtender to use a page method instead of calling our web service method. We will also need to set the ScriptManager.EnablePageMethods property to ‘True’.

Hide image

The method itself must be implemented as a static class method, and must be decorated with the System.Web.Services.WebMethodAttribute attribute.

[WebMethod]
class function GetAutoCompleteList(prefixText: string; 
  count: Integer): TStringArray; static;

Having to apply this attribute should give a hint as to how the AJAX Extensions framework implements a page method call. Instead of forcing us to create an explicit web service interface, it will automatically create one from the static method we’ve declared in our code-behind class, and make that available to the AutoCompleteExtender client script code.

For our example, the implementation of this method will be similar to the one used by our web service method, but will append a ‘Page’ prefix to each element in the returned array, so we can visually differentiate between the two methods when testing. Here is the full source code for the page’s code-behind class:

unit Default;

interface

uses
  System.Collections, System.ComponentModel,
  System.Data, System.Drawing, System.Web, System.Web.SessionState,
  System.Web.UI, System.Web.UI.WebControls, System.Web.UI.HtmlControls, 
  AjaxControlToolkit, AjaxMethods, System.Web.Services, System.Web.Script.Services;

type
  TWebForm1 = class(System.Web.UI.Page)
  {$REGION 'Designer Managed Code'}
  strict private
    procedure InitializeComponent;
  strict protected
    ScriptManager1: System.Web.UI.ScriptManager;
    AutoCompleteExtender1: AjaxControlToolkit.AutoCompleteExtender;
    TextBox1: System.Web.UI.WebControls.TextBox;
    TextBox2: System.Web.UI.WebControls.TextBox;
    AutoCompleteExtender2: AjaxControlToolkit.AutoCompleteExtender;
  {$ENDREGION}
  strict private
    procedure Page_Load(sender: System.Object; e: System.EventArgs);
  protected
    procedure OnInit(e: EventArgs); override;
  private
    { Private Declarations }
  public
    { Public Declarations }
    [WebMethod]
    class function GetAutoCompleteList(prefixText: string; 
      count: Integer): TStringArray; static;
  end;

implementation

{$REGION 'Designer Managed Code'}
/// <summary>
/// Required method for Designer support -- do not modify
/// the contents of this method with the code editor.
/// </summary>
class function TWebForm1.GetAutoCompleteList(prefixText: string;
  count: Integer): TStringArray;
var
  I: Integer;
begin
  SetLength(Result, Count);
  for I := 1 to Count do
    Result[I - 1] := prefixText + I.ToString + 'Page';
end;

procedure TWebForm1.InitializeComponent;
begin
  Include(Self.Load, Self.Page_Load);
end;
{$ENDREGION}

procedure TWebForm1.Page_Load(sender: System.Object; e: System.EventArgs);
begin
  // TODO: Put user code to initialize the page here
end;

procedure TWebForm1.OnInit(e: EventArgs);
begin
  //
  // Required for Designer support
  //
  InitializeComponent;
  inherited OnInit(e);
end;

end.

When configuring our AutoCompleteExtender instance, we only need to specify the ServiceMethod property, as leaving the ServicePath property unspecified indicates that we want it to call a page method:

<cc1:AutoCompleteExtender id="AutoCompleteExtender2"
runat="server"
    targetcontrolid="TextBox2"
    servicemethod="GetAutoCompleteList"
    minimumprefixlength="1" />

We should now be able to run our application, and have the second TextBox call our page method to retrieve its auto-complete list. The result of this call can be seen in Fiddler below:

Hide image
Click to see full-sized image

This time, the Fiddler screenshot shows the raw data that was sent and received during the HTTP calls. As you can see from the Content-Type header value, the AJAX Extensions framework uses JavaScript Object Notation (JSON) to pass the data between the client and server.

    Reacting to Selected Values

By using JavaScript client code, and optionally using AJAX calls to server-side code, it is possible to take action when the user selects a value in the auto-complete list. We will now demonstrate how to make an AJAX call to return additional data from the server when a selection is made. Once again, this can be done by either calling a web service method, or a method implemented in the code-behind for the page.

    Implementing a Web Service Method

Open up WebMethods.pas in the code editor and add the following in the implementation section:

[WebMethod]
function GetSelectionData(SelectedValue: string): string;

The implementation for this method will be pretty basic, and will simply return a string stating what was selected. Add the following code to the implementation section:

function TAjaxMethods.GetSelectionData(SelectedValue: string): string;
begin
  if SelectedValue.StartsWith('error') then
    raise Exception.Create('You requested an error');
  Result := 'You selected ' + SelectedValue;
end;

We have also added some code which will allow us to see how to handle exceptions thrown during the AJAX call. This can be invoked by typing ‘error’ in the TextBox, and selecting any item in the drop-down list.

Now that we have our server-side implementation in place, we need to add the JavaScript code to call it. Before we can do that, we need to register our web service with the ScriptManager component. This is done by adding an asp:serviceReference element to the services element for the ScriptManager component:

<asp:ScriptManager
    id="ScriptManager1" runat="server" enablepagemethods="True">
    <services>
         <asp:ServiceReference path="AjaxMethods.asmx" />
    </services>
</asp:ScriptManager>

If we now run our application in Firefox and invoke the FireBug extension, we can see that a JavaScript proxy has been created for the web service method. In order to see this, switch to the Script tab in FireBug, and select the jsdebug script under the localhost/AutoCompleteTest/AjaxMethods.asmx entry in the drop-down list. Among the other JavaScript listed there, you should see the following (formatting improved for readability):

AjaxMethods.TAjaxMethods.GetSelectionData=   
  function(SelectedValue, onSuccess, onFailed, userContext) 
  {
     AjaxMethods.TAjaxMethods._staticInstance.GetSelectionData(
       SelectedValue, onSuccess, onFailed, userContext); 
  }

This shows us the method we need to use in our JavaScript code, which we will invoke by using the AutoCompleteExtender.OnClientItemSelected client event. The SelectedValue argument will be mapped to the SelectedValue argument in the server-side implementation. The onSuccess argument will be a JavaScript method to call when the server-side method successfully calls back to the client-side code, and the onFailed argument will be a JavaScript method to call if calling the server-side method fails. The userContext argument is not needed here, and we can safely omit it. Here is the complete JavaScript we will be placing in our .aspx file:

<script language="JavaScript">
<!--
function ItemSelected(sender, args)
{
    AjaxMethods.TAjaxMethods.GetSelectionData(args._text, OnComplete,
         OnError);
}

function OnComplete(arg)
{
    alert(arg);
}

function OnError(arg)
{
    alert("Error calling GetSelectionData: " + arg._exceptionType + ' - '
         + arg._message);
}
//-->
</script>

The ItemSelected method is the entry point to the AJAX call, and will be invoked by assigning it to the AutoCompleteExtender1.OnClientItemSelected property:

Hide image

The sender argument is a reference to the AutoCompleteExtender control that initiated the event, and the args argument is an object representing the list item that was selected. If we use FireBug, we can set a breakpoint in this method, and use the Watch window to see the properties this object exposes:

Hide image
Click to see full-sized image

In this case, we are interested in the _text property, which will give us access to the text value of the selected item. Using this information, we then call the AjaxMethods.TAjaxMethods.GetSelectionData JavaScript proxy method, passing in the text value, and JavaScript callback methods for success and failure. In both cases, we simply use the JavaScript alert method to show a message box.

Run the application in a browser, type into the first TextBox (anything other than ‘error’, of course), and select a value in the auto-complete list. You should be greeted with a message box showing you what value you selected:

Hide image

Now type in ‘error’, and select a value. This time you should be shown a different message box, informing us that there was an exception, and providing details of this:

Hide image

Once again, we can use FireBug to add a breakpoint in the OnError event, so we can see what properties that the object passed in the arg argument offers us:

Hide image
Click to see full-sized image

As you can see, the arg argument offers quite a bit of information to assist with diagnosing exceptions, including the class type of the exception, any message text associated with the exception, and a stack trace if available.

    Implementing a Page Method

As with the server method used to populate the drop-down list for the AutoCompleteExtender control, you can implement other AJAX server methods as page methods. This is done in the same manner, with the method declared as a static class method decorated with the WebMethodAttribute attribute.

We will now implement a page method for the second AutoCompleteExtender control, which will provide similar functionality to the web method created above. Open up Default.pas in the code editor, and add the following to the interface section:

[WebMethod]
class function GetSelectionData(SelectedValue: string): string; static;

The implementation for this method will be similar to the web method implementation, but with additional text to allow us to identify that the server method called was indeed the page method. Add the following code to the implementation section:

class function TWebForm1.GetSelectionData(SelectedValue: string): string;
begin
  if SelectedValue.StartsWith('error') then
    raise Exception.Create('The page says you requested an error');
  Result := 'The page says you selected ' + SelectedValue;
end;

Once again, we can use FireBug to determine the JavaScript method proxy that will be generated by this code. In this case, the JavaScript can be observed by selecting Default.aspx in the drop-down list on the Script tab. Examining this will reveal the following method (shown once again with additional formatting applied):

PageMethods.GetSelectionData=   
  function(SelectedValue, onSuccess, onFailed,userContext)  
  {
    PageMethods._staticInstance.GetSelectionData(
      SelectedValue, onSuccess, onFailed, userContext); 
  }

This tells us that the name of the method we want to call is PageMethods.GetSelectionData, but that is the only difference to the web method JavaScript proxy, with the same arguments required when calling it. We will set the AutoCompleteExtender2.OnClientItemSelected property to our ItemSelected JavaScript method, and will change it slightly to cater for the fact that it is now being called by both AutoCompleteExtender controls:

function ItemSelected(sender, args)
{
    if (sender._id == 'AutoCompleteExtender1')
    {
         AjaxMethods.TAjaxMethods.GetSelectionData(args._text, OnComplete,
              OnError);
    }
    else
    {
         PageMethods.GetSelectionData(args._text, OnComplete,
              OnError);
    }
}

We can now run our application, type into the second TextBox, and select a value in the auto-complete list. Once again, we will be greeted with a message box telling us what we selected, but the text will have changed slightly to indicate that the page method was invoked this time:

Hide image

Similarly, typing ‘error’ into the second TextBox, and selecting an entry will show our error dialog, but with additional text letting us know that the error was thrown in the page method:

Hide image

    Implementing the ICallbackEventHandler Interface

In addition to using the AJAX Extensions library to provide a way for client-side JavaScript code to invoke a method on the server, ASP.NET 2.0 introduced a client callback feature which allows for the implementation of a server-side method which can be made available to client-side code. This is done by implementing the ICallbackEventHandler interface, which has the following signature:

ICallbackEventHandler = interface
  procedure RaiseCallbackEvent(Arg: string);
  function GetCallbackResult: string;
end;

The RaiseCallbackEvent procedure is the entry point to the server-side code invoked from the client, and the GetCallbackResult function is responsible for returning a result back from the server to the client. The interface allows for a string parameter to be passed to the server, and a string result to be returned back to the client.

In order to demonstrate implementing this interface, add another TextBox to the web form, along with another AutoCompleteExtender. Set the AutoCompleteExtender.TargetControlID property to the new TextBox, set the AutoCompleteExtender.ServiceMethod to ‘GetAutoCompleteList’, and the AutoCompleteExtender.OnClientItemSelected property to ‘ItemSelected’. The full markup for this new AutoCompleteExtender instance is shown below:

<cc1:AutoCompleteExtender id="AutoCompleteExtender3"
    runat="server"
    targetcontrolid="TextBox3"
    servicemethod="GetAutoCompleteList"
    minimumprefixlength="1"
    onclientitemselected="ItemSelected"
></cc1:AutoCompleteExtender>

We now need to implement the ICallbackEventHandler interface in our code-behind page code. Open up Default.pas in the code editor, and change the type declaration to indicate that it implements the ICallbackEventHandler interface:

type
  TWebForm1 = class(System.Web.UI.Page, ICallbackEventHandler)

Add the following declarations to the public interface section:

procedure RaiseCallbackEvent(Arg: string);
function GetCallbackResult: string;

Now add the following implementations for these methods in the implementation section:

procedure TWebForm1.RaiseCallbackEvent(Arg: string);
begin
  FCallbackResult := 'The callback event says you selected ' + Arg;
end;

function TWebForm1.GetCallbackResult: string;
begin
  Result := FCallbackResult;
end;

Once again, we are only using trivial proof of concept implementations here. When the RaiseCallbackEvent method is called, we build up the string result to return back, and store it in a private string member variable (which will need to be added to the private interface section). GetCallbackResult then simply returns the value of this variable.

Now that we have the interface implemented, we need to add some server-side plumbing code so we can use it. Add the following code to the Page_Load event implementation:

procedure TWebForm1.Page_Load(sender: System.Object; e: System.EventArgs);
var
  Ref: string;
  Script: string;
begin
  Ref := Page.ClientScript.GetCallbackEventReference(Self, 'arg',
    'OnCallbackSelectionData', 'context');
  Script := 'function UseCallback(arg, context) { ' + Ref +  '; }';
  Page.ClientScript.RegisterClientScriptBlock(Self.GetType, 'UseCallback',
    Script, True);
end;

First we obtain a reference to the client-side method we’ll be implementing shortly, which will be responsible for handling the result from our server-side callback. We then use this reference to create a client-side function which we will call from our JavaScript code. In order to do this, we will simply extend our existing ItemSelected function. The new code for this and our new callback method is shown below:

function ItemSelected(sender, args)
{
    if (sender._id == 'AutoCompleteExtender1')
    {
         AjaxMethods.TAjaxMethods.GetSelectionData(args._text, OnComplete,
              OnError);
    }
    else if (sender._id == 'AutoCompleteExtender2')
    {
         PageMethods.GetSelectionData(args._text, OnComplete,
              OnError);
    }
    else
    {
          UseCallback(args._text);
    }
}

function OnCallbackSelectionData(arg, context)
{
    alert(arg);
}

Once again, we use the sender._id property in the ItemSelected method to determine which server-side callback method to invoke. And in the client-side callback method, we simply show the result in a message box.

Run the application in the browser, type some text in the third TextBox, select a value from the auto-complete list, and you should be greeted with a message box similar to the following:

Hide image

    Summary

With the Microsoft ASP.NET AJAX Extensions library and the Microsoft AJAX Control Toolkit, web developers now have an easy way to implement AJAX functionality into their ASP.NET 2.0 applications. This article demonstrated how to use the AutoCompleteExtender control from the AJAX Control Toolkit, and also showed techniques which can be used to invoke server-side methods from client-side JavaScript code.

It also demonstrated how the Fiddler HTTP debugger and FireBug Firefox add-in can be used to assist with developing and debugging AJAX enabled web applications.

The full source code for this article can be downloaded from CodeCentral.

Server Response from: ETNASC04