Nov 14 2006

ASP.NET and JQuery - updating templated controls with AJAH

Posted by admin under Ajax

Continuing our serie on JQuery and ASP.NET we are now gonna create an interface looking like this:

When selecting a filter we want to spawn an Ajax request and update only the table part of the interface:

So far we have used ASHX handlers and returned JSON structures containing business data so to speak - however now we sure would like to have the page generate the pure HTML for the ajax request - just like it generates the HTML for the table if not using ajax at all. Cause in the pages aspx file we have our asp:repeater  code defining the table layout (using the same technique as described here).

So the solution? We are gonna set the ajax request to point to the page (aspx) file - and then try to diffrentiate that ajax call from a regular page request - cause if it's ajax we should just return the html the repeater spits out.

First some standard code:



    protected DataTable GetData(string sFilter)
    {
        string sFilterToUse = "";
        if (sFilter == "Mr")
            ... code removed for clarity...

        return Microsoft.ApplicationBlocks.Data.SqlHelper.ExecuteDataset(ConfigurationSettings.AppSettings["connstring"],
             CommandType.Text, "select * from employees" + sFilterToUse).Tables[0];
    }


    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            rptTable.DataSource = GetData(Request["filter"]);
            rptTable.DataBind();
...



In the rptTable_ItemDataBound we set the labels etc defined in the template. Just like the original code so far.

Now - lets add the JQuery stuff:



    <script type="text/javascript"> 
$(document).ready(function() 
{

           $('#Select1').change(function() {      
                var str = $('#Select1').val();
                var sUrl = 'default.aspx?w=callback&filter=' + str;
                AjaxGetHTML(sUrl);
              });    
            
     
})

function AjaxGetHTML(sUrl)
{
    $.get(sUrl,function(result)
        {
         $('#repeater1').html( result );
        });
 }
...
...
</script>
    Select filter: 
        <select id="Select1">
            <option selected="selected" value="All">All</option>
            <option value="Mr">Mr</option>
            <option value="Dr">Dr</option>
            <option value="Ms">Ms</option>
            <option value="Mrs">Mrs</option>
        </select>
...
...



Pretty basic. We add a handler for Select1 change event and from there we create a url string - based on the selected value, however we calso add an extra parameter w=callback. 

In other words if the user selects filter "Ms" the url will be

default.aspx?w=callback&filter=Ms

And we call AjaxGetData which retrieves the data from that url and puts it into a div (which is the div containg the repeater). Meaning the repeaters html code will be totally replaced.

So far it seems fine - now lets go back to look at the serverside code - what do we do in the Ajax callback (i.e w=callback?):

This is how Page_Load looks like:



    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            if (Request["w"] != null && Request["w"] == "callback")
            {
                rptTable.DataSource = GetData(Request["filter"]);
            }
            else
                rptTable.DataSource = GetData("");
            
            rptTable.DataBind();
            if (Request["w"] != null && Request["w"] == "callback")
            {
                //Just return the rptTable html...
                Response.Cache.SetCacheability(HttpCacheability.NoCache);
                string sRet = GetHtml( rptTable );
                Response.Write(sRet);
                Response.End();

            }
        }



We create the repeaters datasource as usual and databind it, however when we are inside a callback we call a function GetHtml (which generates the html for the control sent in to it) and just write that back to the client!

The last secret is the GetHtml function:



    //Place this function in a helper class instead - but kept in form class for clarity here
    public static string GetHtml(Control oCtrl)
    {

        StringBuilder oBuilder = new StringBuilder();
        HtmlTextWriter oWriter = new HtmlTextWriter(new StringWriter(oBuilder));
        try
        {
            oCtrl.RenderControl(oWriter);
        }
        finally
        {
            oWriter.Close();
        }
        return oBuilder.ToString();
    }




That code is taken from Nigel Liefrinks article at codeproject 

 Last 1: About the AJAH in the header - no I have NOT mispelled ajax. Cause this technique is not Asynchronous Javascript And Xml - but rather Asynchronous Javascript And Html.

 Last 2: About the strange filtering code I use in GetData(). Not production quality - however I just wanted to avoid the standard comment - "your code is volnerable to sql injection"