Introduction
This article goes over integrating AJAX into your website without using Atlas or controls that are already wired up for you. This is useful for environments where you cannot use Atlas. It's also interesting if you'd like a lower level look at how asynchronous client server communication works and the issues involved. The techniques covered include embedding JavaScript in the web application's assembly, registering variables from C# codebehind, and using AJAX to communicate with C# server side code.
Using the Code
To deploy the web application, just unzip the AJAXIntegration.zip into the inetpub\wwwroot directory. Then use the IIS snap in to create an application on the AJAXIntegration directory.
Project
One of the most common AJAX applications is an autocomplete text box. These are useful for maintaining data integrity and keeping input forms relatively uncluttered and intuitive. The key component is a nice JavaScript library from http://script.aculo.us/. This has, among other neat features, a good autocomplete implementation.
Points of Interest
The first thing we create is a web user control with a textbox
and the necessary decoration and methods to hook into the scriptaculous
library. I saved the scriptaculous
library right in the root of my web project in a folder called Scriptaculous. The asp.net code for the user control looks like this:
<asp:TextBox id="TextBox1" runat="server" Width="300px">
</asp:TextBox>
<div id="TextBoxUpdate" runat="server" style="BORDER:
#888 1px solid; DISPLAY: none; WIDTH: 250px;
CURSOR: pointer; POSITION: absolute; HEIGHT: 300px;
BACKGROUND-COLOR: white"></div>
Notice how there's no mention of the JavaScript. All the magic is in the codebehind, in the PreRender
event. This event is called after most of the work to build the page is done. It is the right place to register client side scripts:
private void AutocompleteTextBox_PreRender(object sender,
System.EventArgs e)
{
this.Page.RegisterArrayDeclaration(
"Tallan_AutocompleteTextBox","'"+
SearchBox.ClientID+"','"+SearchBoxUpdate.ClientID+
"','"+"http://localhost/AJAXIntegration/Fetch.aspx
?parameterId="+Parameter+"'");
string commonScriptKey = "AutocompleteTextBox";
if ( !Page
.IsClientScriptBlockRegistered(commonScriptKey) )
{
using (System.IO.StreamReader reader =
new System.IO.StreamReader(
typeof(AutocompleteTextBox).Assembly
.GetManifestResourceStream(typeof(
AutocompleteTextBox),
"AutocompleteTextBox.js"))
)
{
String script = "<script language="'javascript'"
type='text/javascript' >\r\n<!--\r\n" +
reader.ReadToEnd() + "\r\n//-->\r\n</script>";
this.Page.RegisterClientScriptBlock(
commonScriptKey, script);
this.Page.RegisterStartupScript(commonScriptKey,
"<script language="'javascript'" type='text
/javascript' >\r\n<!--\r\n
Tallan_AutocompleteTextBox_Init(); \r\n//-->
\r\n</script>");
}
}
}
The key technique here is using Page.RegisterArrayDeclaration
, Page.IsClientScriptBlockRegistered
, Page.RegisterClientScriptBlock
and Page.RegisterStartupScript
to handle the dynamic nature of ASP.NET user controls. What I mean by this is that a user control can be deployed on any page under any number of parent controls. Therefore its id will vary depending on where it resides. However, C# codebehind has access to that id, namely [some control].ClientId
. So when the script is registered to the page, the JavaScript can operate with the correct controls on the client side. The Page.RegisterArrayDeclaration
method will create a new JavaScript array in the HTML code that is pushed to the client. If the array exists, it will append to it. The other register
methods are used to only register the script if one is not already present. This will be useful when you want to use more than one control on the same page, as I will in the example.
The other point of interest in the above code is how the scripts are fetched to be registered. In the Page.RegisterStartupScript
call, I used inline text which will get written to the client as is. In the Page.RegisterClientScriptBlock
however, I used a StreamReader
to access an "Embedded Resource". The way this works is you make a JavaScript file and in Solution Explorer, right click and choose Properties. In the Build Action property, select the Embedded Resource choice. Now when you compile the project, this text file will be available to read as is shown above. As a little side note, if your JavaScript changes from these embedded resources aren't propagating to your deployed application, try rebuilding the project and redeploying it. This will make sure you have the freshest available copy of the script in the assembly.
The JavaScript file AutocompleteTextBox.js that is registered to the page contains an initialization method which is called by the page upon startup. It is this method that assigns the AJAX behavior to the textbox
:
function Tallan_AutocompleteTextBox_Init() {
try
{
if (!Tallan_AutocompleteTextBox_BrowserCapable())
{ return; }
for(var i=0;i<Tallan_AutocompleteTextBox.length;
i+=3 ){
new Ajax.Autocompleter(
Tallan_AutocompleteTextBox[i],
Tallan_AutocompleteTextBox[i+1],
Tallan_AutocompleteTextBox[i+2], {
paramName: "search" });
}
}
catch(e){}
}
Basically, the whole linkup is just instantiating a:
new Ajax.Autocompleter
The constructor takes three parameters:
- the client id of the text box to autocomplete
- the client id of a
div
that will pop up and display the results - the url of a resource that will pass back autocomplete choices
- the parameters for various
scriptaculous
options
The last thing to go over is the resource that supplies autocomplete choices. You can look up the scriptaculous
parameters on their website as they continue to release updates and have a good documentation wiki.
Scriptaculous
AJAX looks for a simple page that renders only an HTML list of the form:
<ul><li>autocomplete choice 1</li>
<li>autocomplete choice 2</li></ul>
This is where we can create an aspx page (I called it Fetch.aspx) to hook into some server data source and render dynamic or cached autocomplete content. First, create a new web form in your project and make sure to delete everything in the generated source besides the page tag. This includes the form
tag, html
tag, everything. The reason for this is that Internet Explorer won't display the popup autocomplete div
if the page is more complicated than just a simple <ul>
list. Then, you're ready to write the following code in the Page_Load
event:
string match = Request.Form["search"].ToLower();
Response.Write("<ul>");
foreach( string s in sample )
{
if( s.ToLower().IndexOf(match) == 0 )
{
Response.Write("<li>"+s+"</li>");
}
}
Response.Write("</ul>");
Notice how we get the "search
" parameter from the Request.Form
object. The name of this parameter is configured in the Ajax.Autocompleter
constructor which is called in the Tallan_AutocompleteTextBox_Init
function discussed above. The sample array is just a string[]
of sample data. You can easily get your data from a DataTable
using the Select
method. In the AutocompleteTextBox
control, I also included a property called Parameter
which ends up being passed to Fetch.aspx in the query string like http://localhost/AJAXIntegration/Fetch.aspx?parameterId=[Parameter]. You can access this and any other properties you wish to pass from each individual control via the Request.QueryString
object.
One last thing to note is that the SmartNavigation
attribute confuses InternetExplorer's asynchronous request, at least when it comes to scriptaculous' implementation. Therefore, disable SmartNavigation
on any page where the control will be used.
Conclusion
Now just deploy the code and try it for yourself. You can also open the project in Visual Studio or Sharp Develop and browse the code. Remember that you can enable script debugging in Internet Explorer by going to Tools, Options, Advanced and unchecking the "Disable script debugging" option. Doing so will allow you to place break points in the js files from the Scriptaculous folder and see what's going on during the asynchronous calls. I did not cover the full implementation details for the sake of brevity. Therefore, please don't hesitate to ask questions.
License
This article has no explicit license attached to it, but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below. A list of licenses authors might use can be found here.