Over the past few months I have been toying with Ajax and .NET via the Ajax.NET Professional Library and my first few attempts left me feeling that Ajax was not very useful. Then I recently had a specific task to complete and it seemed to be a perfect candidate for Ajax. The task was very simple, get a list of Albums by an Artist. This functionality is of course part of a much larger on-line music app I was constructing but I needed to start with something small. The UI was very simple a TextBox to enter an Artists’ Name and a Table to display the Albums. Since this was such a simple task I decided to spice it up with some AJAX.
Part 1: Objects and Data
The first thing we need to do is add anAjax "Auto-Complete" like function to a TextBox. This type of example is covered in more detail here The "Auto-Complete" functionality is very simple: A user starts typing in the search text box. The Search box has an "OnKeyUp" JavaScript Event defined. This JS Event triggers a function that sends the letters in the text box to an ASP.NET function. The ASP.NET function processes the query and returns the results to the JS function. The JS function them binds the results to Select Box.

One thing I have found with this is that results are bound to the value attribute of the Select/Option as well as the text value:
-
<option value="Metallica">Metallica</option>
This results in the Select box using the display text as the value as well. This may work for some apps but without a value we only have the Artist Name(s) to use for our second AJAX function. The second function will be to search for a list of albums by the selected artist. Since the data is normalized, the Albums table is linked to the Artists table via the ArtistID. This requires a little hacking.
What we need is a Select Box that looks like this:
-
<select>
-
<option value="12">Metallica</option>
-
<option value="16">Megedeth</option>
-
<option value="19">Ozzy</option>
-
</select>
Binding data to the value attribute requires returning the Artist Search results as an Object Array.
This requires us to create an Serializable Artist object using the [Serializable] attribute at the start of the class. This will allow us to return an ArrayList of Artists but Serialized in XML so the browser can read them.
-
[Serializable]
-
public class EmployeeObject
The second part of this task is to get the Albums based on the Artist ID. This part requires invoking an AJAX call that will send the selected ArtistID to the back-end (WebService, XML DataSet, SQL) to get the Albums and then display the results in as an html table.
*NOTE: I first tried to bind my results to a DataList but this resulted in JavaScript Errors and a blank DataList. This will not work because a DataList in a .NET Server Control and JavaScript/AJAX is Cliet-side control. The trick is to bind the results to a string array in JavaScript and then bind that to a DIV.
Part 2: Diving In
*QUIRK: When using Server.MapPath the path "/ajax" gets pre-pended to the file path.*
For these examples we are using local XML Files.
Project Setup:
For this article I am using 2 projects.
AJAXWebUI - WebApp
Core - Core Business/Data Logic
WebApp Setup:
Create a reference to AJAX.dll
Add an HTTPHandler to the web.config
-
<httpHandlers>
-
<!-- Register the ajax handler -->
-
<add verb="POST,GET" path="ajax/*.ashx" type="Ajax.PageHandlerFactory, Ajax" />
-
</httpHandlers>
Create the two XML files in a sub folder named "ajax": ArtistData.xml and AlbumsData.xml. See attched code for sample data.
In the main web form add a table with a 4 controls:
1) txtArtists = TextBox to type the ArtistName in.
2) matches = A SelectBox with an onclick event which will be used to send the ArtistID to the AlbumSearch method we will be creating.
3) txtArtistID = Hidden to hold the selected ArtistID
4) htmlOutput = An empty DIV when we will be creating a table of Albums
-
<select onclick="MatchSelected(this);" style="visibility: hidden" id="matches" /><input type="hidden" id="txtArtistID" />
-
<div id="htmlOutput" />
In the Page_Load we are going to add a reference to the AJAX Object and add a JavaScript event to the txtArtists box.
-
private void Page_Load(object sender, System.EventArgs e)
-
{
-
Ajax.Utility.RegisterTypeForAjax(typeof(WebForm1));
-
this.txtArtists.Attributes.Add("onKeyUp", "GetArtist(this.value);");
-
}
We have a few more methods and reference to add but they won't make sense until we create some objects that we will be using.
Core Setup:
Create a new class library and add a reference to System.Web.
Create 2 classes.
MusicManager.cs - This will have the 2 search methods.
-
public ArrayList SearchArtist(string artistname)
-
public DataSet SearchAlbumsByArtist(string artisid)
SearchArtist - return an ArrayList of Artists objects.
SearchAlbumsByArtist - Return a DataSet of Albums.
You can look at the source files for furthure details.
Artists.cs - This is a very basic class but is Serialized
-
[Serializable]
-
public class Artists
-
{
-
public string artistName;
-
public string artistID;
-
}
And that's it. These 2 classes do not have to be in their own Project. I have only done this to show the sepration of the UI and the code.
Back to the Web App.
In the main page you'll need to reference the Core.MusicManager class.
-
private Core.MusicManager musicMgr = new Core.MusicManager();
Next are our two search methods:
As you can see both of these methods are very simple.
They take in a parameter, pass it to the MusicManager and get some data back.
-
[Ajax.AjaxMethod()]
-
public ArrayList GetArtist(string artistName)
-
{
-
ArrayList artistList = new ArrayList();
-
artistList = musicMgr.SearchArtist(artistName);
-
return artistList;
-
}
-
-
[Ajax.AjaxMethod()]
-
public DataSet GetAlbumByArtist(string searchCriteria)
-
{
-
DataSet dsAlbums = new DataSet();
-
dsAlbums = musicMgr.SearchAlbumsByArtist(searchCriteria);
-
return dsAlbums;
-
}
Part 3: AJAX and the UI
The next part is to hook up our search methods and results object to AJAX.
In the HTML we have already created the our controls so now we need some JavaScript functions:
First create a variable for the matched items (search results).
-
var matchList = document.getElementById("matches");
Next create a function that will be called by the onKeyUp event.
-
function GetArtist(searchCriteria) {
-
if (searchCriteria) {
-
-
WebForm1.GetArtist(searchCriteria, GetArtist_CallBack);
-
} else {
-
//clear the states dropdown
-
matchList.style.visibility = "hidden";
-
}
-
}
You'll have noticed a GetArtist_CallBack function that AJAX will pass it's response to.
This next block of code is the bread and butter of this whole app.
First we are checking for any errors.
Then we check to see if we got any results from our search and if we didn't we are going to hide our Select Box (matchList).
Provided that we get some results we will make the matchList visible, clear out any previous results and then set the number of items to the number of search results.
The last this we do is the tricky part. We are iterating over the results and we are inserting the items into our matchList as Options with a text of Artists Name and a value of the ArtistID.
[js]
function GetArtist_CallBack(response)
{
//if the server side code threw an exception
if (response.error != null)
{
alert(response.error); //we should probably do better than this
//return;
}
//if we didn't get what we expect, or didn't get any matches
if (!response.value[0] || response.value[0].length == 0)
{
matchList.style.visibility = "hidden";
return;
}
matchList.style.visibility = "visible";
matchList.options.length = 0; //reset the s