Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML

SAL - Simple AJAX Library

4.58/5 (22 votes)
5 Oct 20055 min read 1   774  
An article on AJAX [Asynchronous JavaScript and XML], a simplified version written in JavaScript, demonstrated in ASP.NET. Can be used with any server side scripting language.

SAL - Simple Ajax Lib

Introduction

This article presents a simplified AJAX library written in JavaScript, hopefully many developers will find it useful.

AJAX is an exciting new technology and will change the way we develop our web applications.

Basically the library comprises of two methods, no classes or anything fancy, (I said it was simple). These two methods were designed with ease of use in mind. One allows flexibility by being able to pass the response to a JavaScript function, which allows you to do anything JavaScript can do with the returned data/response. The other sets the innerHTML property of the passed object.

Background

I had heard a lot about this new AJAX technology and seen some examples on the web which looked really cool, so I thought I'd do some R&D on the subject.

The first thing I do when researching new technologies is look around the web for some libraries or code, and read, read, and read some code. As usual some are useful, a lot are overly complicated. So I take the useful and overly complicated code, and re-work it into something simple and easy to use.

My background is PHP and Linux, but now I'm a Microsoft .NET developer. Because of this .NET developers may or may not notice that I use more traditional techniques than the new ASP.NET way. This example uses ASP.NET and JavaScript.

The library itself can be used with multiple server side languages. Prepare to be amazed by the jaw-dropping simplicity of this code.

Using the code

Well let's get down to it...

The first thing to do is include the ajax.js JavaScript file in your web page like this:

HTML
<script language="javascript" src="ajax.js"></script>

Now we can use the two JavaScript functions in the ajax.js file.

The first function in the library, and the one that I use most, is SetInnerHTMLFromAjaxResponse(url, obj_id). Here is an example of how to use it in a web page:

HTML
<input type="button" 
  onclick="SetInnerHTMLFromAjaxResponse('?button=1','div_to_put_html')"
  value="Get Some Html From The Server" ID="Button1" NAME="Button1" />
<div id="div_to_put_html"></div>

The first argument '?button=1' is the URL to send the request. Seasoned web developers will know that this is submitting the variable "button" with a value of "1" to the current page. You can of course submit the request to anywhere on the internet, but essentially to a server that will know what to do with the request and return some HTML. The function will place the returned HTML/response and place it in the div we specified.

You can call this function from anywhere in the JavaScript.

JavaScript
function GetFilteredCustomerTable() {
    var name = document.getElementById('cust_surname').value;
    var country = document.getElementById('cust_country').value;
    var min_orders = document.getElementById('min_orders').value;
    SetInnerHTMLFromAjaxResponse('?action=get_customers_table&name='+name+
          '&country='+country+'&min_orders='+min_orders,'div_to_put_html')
}

You can see that we are passing more parameters to the page in this example. These parameters can be used in the server side script to select/filter records from a database, create some HTML from the results and return it.

Now onto the second JavaScript function: PassAjaxResponseToFunction(url, callbackFunction, params). This will pass the response to the callback function. The params argument is optional. The JavaScript to use would look something like this:

JavaScript
<input type="button" 
  onclick="PassAjaxResponseToFunction('?getsomecsvdata=1', 
          'FunctionToHandleTheResponse', 
          '\'div_0\',\'div_1\',\'div_2\'');"
  value="Pass The Response To A Function" ID="Button2" NAME="Button2" />



function FunctionToHandleTheResponse(response, d0, d1, d2){
    //we are expecting r to look like 'value1,value2,value3'
    var data = response.split(',');
    document.getElementById(d0).innerHTML = data[0];
    document.getElementById(d1).innerHTML = data[1];
    document.getElementById(d2).innerHTML = data[2];
}

Again the call to PassAjaxResponseToFunction() can be called from a JavaScript event or another JavaScript function. The FunctionToHandleTheResponse(response, d0, d1, d2) is a JavaScript function written to handle the returned response when it has been successfully received from the server. I think that only constants (strings, ints, etc.) and globals will actually be in scope when being passed in the params string.

Passing the optional param argument is not necessary as the same result could be achieved by doing this:

JavaScript
<input type="button" 
  onclick="PassAjaxResponseToFunction('?getsomecsvdata=1', 
                          'FunctionToHandleTheResponse');"
  value="Pass The Response To A Function" ID="Button3" NAME="Button3" />

function FunctionToHandleTheResponse(r){
    //we are expecting r to look like 'value1,value2,value3'
    var data = r.split(',');
    for(var i=0;i<data.length;i++){
        document.getElementById('div_'+i).innerHTML = data[i];
    }
}

Although, passing 'div_' as a parameter may be useful for code re-usability.

And that's all there is to it. Hopefully you can see how easy this will be to use.

The JavaScript Source Code

I'm not going to spend much time explaining the source. I will point out that setting debug = true; is helpful for seeing errors and seeing the response before it is rendered. Viewing the source in the browser will only show you the empty divs and not the source that has been returned.

There's not much to the ajax.js JavaScript file, so here is the code:

JavaScript
/**
SAL - Simple Ajax Lib. 23-Sep-2005
by Nigel Liefrink
Email: leafrink@hotmail.com
*/

var debug = false;
/**
<summary>
Browser Compatability function.
Returns the correct XMLHttpRequest 
  depending on the current browser.
</summary>
*/
function GetXmlHttp() {
  var xmlhttp = false;
  if (window.XMLHttpRequest)
  {
    xmlhttp = new XMLHttpRequest()
  }
  else if (window.ActiveXObject)// code for IE
  {
    try
    {
      xmlhttp = new ActiveXObject("Msxml2.XMLHTTP")
    } catch (e) {
      try
      {
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP")
      } catch (E) {
        xmlhttp=false
      }
    }
  }
  return xmlhttp;
}


/**
<summary>
Gets the response stream from the passed url, and then calls
   the callbackFuntion passing the response and the div_ids.
</summary>
<param name="url">The url to make the request
            to get the response data.</param>
<param name="callbackFunction">The function to call after 
the response has been recieved.
The response <b>must</b> always 
be the first argument to the function.</param>
<param name="params"> (optional) Any other parameters 
you want to pass to the functions.
(Note: only constants/strings/globals can be passed
       as params, most variables will be out of scope.)
</param>
<example>
    <code>
PassAjaxResponseToFunction('?getsomehtml=1', 
              'FunctionToHandleTheResponse', 
              "\'div1\',\'div2\',\'div3\'');

function FunctionToHandleTheResponse(response, d1, d2, d3){
    var data = response.split(';');
    document.getElementById(d1).innerHTML = data[0];
    document.getElementById(d2).innerHTML = data[1];
    document.getElementById(d3).innerHTML = data[2];
}
    </code>
</example>
*/
function PassAjaxResponseToFunction(url, callbackFunction, params)
{
  var xmlhttp = new GetXmlHttp();
  //now we got the XmlHttpRequest object, send the request.
  if (xmlhttp)
  {
    xmlhttp.onreadystatechange = 
            function ()
            {
              if (xmlhttp && xmlhttp.readyState==4)
              {//we got something back..
                if (xmlhttp.status==200)
                {
                  var response = xmlhttp.responseText;
                  var functionToCall = callbackFunction + 
                                 '(response,'+params+')';
                  if(debug)
                  {
                    alert(response);
                    alert(functionToCall);
                  }
                  eval(functionToCall);
                } else if(debug){
                  document.write(xmlhttp.responseText);
                }
              }
            }
    xmlhttp.open("GET",url,true);
    xmlhttp.send(null);
  }
}


/**
<summary>
Sets the innerHTML property of obj_id with the response from the passed url.
</summary>
<param name="url">The url to make the request 
to get the response data.</param>
<param name="obj_id">The object or the id of 
the object to set the innerHTML for.</param>
*/
function SetInnerHTMLFromAjaxResponse(url, obj_id)
{
  var xmlhttp = new GetXmlHttp();
  //now we got the XmlHttpRequest object, send the request.
  if (xmlhttp)
  {
    xmlhttp.onreadystatechange = 
            function ()
            {
              if (xmlhttp && xmlhttp.readyState==4)
              {//we got something back..
                if (xmlhttp.status==200)
                {
                                  if(debug)
                                  {
                    alert(xmlhttp.responseText);
                  }
                  if(typeof obj_id == 'object')
                  {
                    obj_id.innerHTML = xmlhttp.responseText;
                  } else {
                    document.getElementById(obj_id).innerHTML = 
                                          xmlhttp.responseText;
                  }
                } else if(debug){
                  document.Write(xmlhttp.responseText);
                }
              }
            }
    xmlhttp.open("GET",url,true);
    xmlhttp.send(null);
  }
}

ASP.NET - Using the code, the server side

For ASPX pages, I will create a method to check if the request is an AJAX request, then only return what is needed in the response. It is important to call Response.End(); when we have finished returning what we need.

C#
///Standard ASP.NET event
private void Page_Load(object sender, System.EventArgs e)
{
    HandleAjaxEvent();

  //do all the normal rendering for the page...
}

/// <summary>
/// Checks the query string to see if the request is an ajax event.
/// If it is, only return the specific data/html needed.
/// Then call Response.End() so as not to render
/// the rest of the page to the Ajax response.
/// </summary>
private void HandleAjaxEvent()
{
    string bNum = Request.QueryString["button"];
    //if something that indicates an ajax request, just return the data only.
    if(bNum != null && bNum.Length > 0)
    {
        switch (bNum)
        {
            case "1":
                //demonstrates the use of the GetHtml() function.
                //if you wanted to use controls that 
                //are created using the designer on the aspx page,
                //you can set their visibility to false initially.
                //then temporarily set visibility to true,
                //call GetHtml()
                //This would be the best thing to do with 
                //a repeater, trying to create one in code is a lot of work.
                //(or just use for loops to create html.)
                Label l =  new Label();
                l.Text = "Ajax is hot!";
                l.BackColor = Color.Honeydew;
                l.BorderWidth = 6;
                l.BorderStyle = BorderStyle.Groove;
                l.BorderColor = Color.Goldenrod;
                Response.Write(GetHtml(l));
                Response.End();
                break;
                
            case "2": //Get Customer Data
                //Just return some csv data
                string name=Request.QueryString["name"];
                Response.Write(GetCustomerDetailsByName(name));
                Response.End();
                break;
                
            case "3": Return a Filtered DataGrid
                //create a data grid using the 
                //min_orders filter and return the html.
                DataGrid dg = new DataGrid();
                dg.AutoGenerateColumns = true;
                string min_orders=Request.QueryString["min_orders"];
                DataTable dt = GetCustomersDataTable();
                DataView dv = new DataView(dt);
                dv.RowFilter="Orders > "+min_orders;
                dg.DataSource = dv;
                dg.DataBind();
                Response.Write(GetHtml(dg));
                Response.End();
                break;
                
        }            
    }
}

///<summary>Get customer csv string 
///  from the data base by name.</summary>
public string GetCustomerDetailsByName(string name)
{
    return "Nigel,Liefrink,27";
    //go get some data in the database 
    //and return it as a csv.
}

///<summary>Get a table from the database.</summary>
public DataTable GetCustomersDataTable()
{
        //Go to the Database and return a table. 
    return new DataTable();   
}


/// <summary>
/// Helper to get a html string
/// representation of the passed Control.
/// </summary>
/// <param name="c">Control to return Html for</param>
/// <returns>Html of control</returns>
private string GetHtml(Control c)
{
    StringBuilder sb = new StringBuilder();
    HtmlTextWriter tw = new HtmlTextWriter(new StringWriter(sb));
    try
    {
        c.RenderControl(tw);
    }
    finally
    {
        tw.Close();
    }
    return sb.ToString();
}

Take note of the use of the GetHtml(Control c) function and how you can get controls to render only themselves and return the HTML to the page. This function should either be in a BasePage class or in a helper/utility class if you plan to render controls in this way.

Getting the demo project working

To get the demo project working, unzip the sal_demo.zip file to an appropriate location like wwwroot, but anywhere will do. Create a virtual directory in Information Services Manager/IIS under the 'Default Web Site' with an alias of 'sal_demo' and the directory path referencing the sal_demo folder you unzipped. Opening the project in Visual Studio, you should now be able to compile/debug/run the demo project.

Points of Interest

  • View state etc. is not taken into account for controls when they are rendered by the server by GetHtml(Control c). Take a look at this article: AJAX Was Here - Part 1: Client Side Framework or Instant AJAX: Applying AJAX to your existing Web Pages, if that is an issue for you.
  • JavaScript doesn't support threading (someone please tell me I'm wrong). If an AJAX request takes a long time to complete, no other AJAX request can complete until the first one finishes. This can be seen in the example project if you click on the LongAjaxRequest button, and try clicking on another button. (I've tried setInterval/Timeout.)
  • This is my first article, hope you like it.

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