Click here to Skip to main content
13,046,337 members (129,132 online)
Click here to Skip to main content
Articles » Web Development » Ajax » General » Revisions
Add your own
alternative version


14 bookmarked
Posted 4 Oct 2011

Ajax dataGrid user control by using Jquery

, 4 Oct 2011
Rate this:
Please Sign up or sign in to vote.
Ajax dataGrid user control by using Jquery
This is an old version of the currently published article.


In the 1st part, I describe how to implement Jquery Ajax call in the page;
In this part, I will introduce the Ajax datagrid user control by using Jquery and the Ajax function in part one.


The Ajax grid control actually is similar with Microsoft grid control. It has 2 parts, the paging index and the grid. In the grid there is 2 main parts, header and content. Header are static and defined in resource file in server in most of time, content are dynamic from database query. Microsoft datagrid or gridview use binding method to bind the result and render in server side. Our task is bind to result and render in client side.

The reason why I didn't use Microsoft Ajax, because we want to make the Ajax lighter and more flexible. the Microsoft Ajax will still bind and render the grid in server side, that consumes more resource to build and format the grid and also transfer more redundant data like html tag, style and static command names or links. My idea is that we return datatable like JSON format result to client, let client bind the result with predefine schema, render table in client side, so all binding, rendering, styling and customization jobs will be done in client so that makes traffic and server lighter.

Demo Part by Part

To make it work, the page need inherit from the Jpage which I demo in the part one, because it will fire Ajax call, and also uses an Ajax datagrid which I will demo underneath. the grid looks like this:


Let me describe the Ajax dataGrid part by part:

Part 1: In ascx File

<%@ Control Language="c#" AutoEventWireup="false" Codebehind="JgridCtl.ascx.cs" 


    TargetSchema="<a href=""%">"%</a>>


   <span id="pageIdx"></span>

   <span id="loading" class="hide">  

   <span class="ProgressText">loading......</span></span><br/>

   <asp:PlaceHolder ID="JgridHolder" runat="server"></asp:PlaceHolder>


It is pretty simple, includes an HTML span which holds paging index content, a HTML span which holds waitting message and a PlaceHolder which holds the grid.

Part 2: In Code Beind, ascx.cs File

There is 2 goals in the C#:

  1. loading a template into the placeHolder, the template will hold the basic grid structure and header; the idea is like <asp:TemplateColumn>. Because the structure and the header are depend on different pages.
  2. initialize data for JavaScript and load the Ajax datagrid JS file.

The code shown below (read the comment):

namespace YourNameSpace.UserControls{
public class JgridCtl : System.Web.UI.UserControl
    #region WebControls
    protected PlaceHolder JgridHolder;
    private ITemplate _template;

    #region Properties
    //set a template to hold HTML table for header
    public ITemplate Template {
    get { this.EnsureChildControls(); return _template; }
    set { this.EnsureChildControls(); _template = value; }
    //you JS file path
    public string PathToJgridPageScript {
    get { return Page.ResolveUrl("~/YourPath/JgridCtl.js") + "?version=" + 
        Config.Version; }

    #region Web Form Designer generated code
    override protected void OnInit(EventArgs e) {
    //load the template into the placeHolder
    if (_template != null) {
    #region Events
    private void Page_Load(object sender, System.EventArgs e) {
    //initialize javascript data
    if (!Page.IsPostBack) {
    StringBuilder sb = new StringBuilder();
    sb.Append("var Jgrid={};");
        "Your resource string that construct the index"));
        "Your resource string that show when no query result"));
        "JgridCtl_Block", sb.ToString(), true);
    Page.ClientScript.RegisterClientScriptInclude(this.GetType(), "JgridCtl", 

    #region Helper Methods
    //load column headers
    internal void ColLocalize(string id, string resource) {
    try {
        Label tmpTxt;
        tmpTxt = (Label)this.FindControl(id);
        tmpTxt.Text = resource;

Part 3: JS File

Be patient to read the code and comment, it is not big though(less than 4K).

//TB and schema will be defined in page level, all these variable are 
//essential and enforce check in the code.
//TB is html table id, schema is the string array that must be match with both 
//table columns and JSON return headers (they are datatable headers or
//anonymous type properties in C# result)
var TB=schema=currentPg=currentPerPage=param=null;
//all these 3 function must be defined in page level.
var pageFuns=['JgridReady','getParameter','customTable'];

//html methods, just a short cut to construct html.
function td(C){return '<td>'+C+'</td>';}
function pageLink(Idx,C){return(' '+link('javascript:goPage('+Idx+')',C,Idx));}
function link(L,C,N){
    return('<a class="HyperLink" name="'+N+'" href="'+L+'">'+C+'</a>');}

//page methods
//remember the pageheader control in part one, when page is loaded,
//$(document).ready will forward the call to page level pageReady();
//we check these 3 essential functions whether are defined in page level 
//here and fire another page level JgridReady().
function pageReady(){
var missing=[];
if(missing.length>0){alert('missing function: '+missing.join());return;}
    'Variable TB or schema is not initialized in JgridReady().');}

//a search click function, call getParameter() to construct parameter object
function OnClickSearch(){
    'Variable param or currentPerPage is not initialized in getParameter().');return;}

//when page index click, fire Ajax call for query.
function goPage(pgNum){
//call server 'getList' method and return to callback method, so in the 
//page level, it must provide a 'protected getList()' method for ajax call, 
//or you can improve it by setting the method name in variable to make it dynamic. 
//callAjax() is define in Jpage in <a href="/KB/ajax/AjaxJquery.aspx">part one</a>.

function getListCallBack(result){
//in the result, it has 2 parts, the total amount of the result and the result list
//convert the JSON result list to an Object array match with its header.
var list=jstrToObjAry(result.list);
//construct the paging index link.
//clear the old content before render
//build a plain table that match the result with the schema which 
//defined in the page level
//formating and styling the table
//customize the table, do exact work that you want, like add command
//links in every row.

//enable or disable the control when Ajax call back or Ajax call processing
function enableCtls(F){

//enable or disable the paging index when Ajax call back or Ajax call processing
function enablePgLinks(F){$('#linkWrapper a').each(function(){(F)?$(this).attr(
//format table, usually set some columns invisible(like id)
function formatTable(tbId){$('#'+tbId).find(' tr:first .hideCol').each(
   function(){$('#'+tbId+' tbody td:nth-child('+($(

//general methods
//this is optional, it gets some control value to construct parameter
function getSort(V){return (Val('select[id*=ddlSortExpr]')==V)?Val(

function Val(selector){return $(selector).val();}

//get column index, the id is define in your page level, html table template.
function tdIdx(id){return $('#'+id).index();}

//build index header infomation
function rowCountHeader(total,pgNum,rowNum){
if(total<=0){return ("<span>"+Jgrid.NoRsult+"</span>");}
var startIndex=(pgNum-1)*currentPerPage+1;
return Jgrid.Pager.replace('{0}',startIndex).replace('{1}',

//build paging index
function getPageLink(total){
var idx1=(0!=currentPg%10)?currentPg-currentPg%10+1:(currentPg-10)+1;
var idxLast=Math.ceil(total/currentPerPage);
var A=[];
A.push('<span id="linkWrapper">');
for(var i=idx1;i<idx1+10&&i<=idxLast;i++){if(i==currentPg){
    A.push(' '+i);}else{A.push(pageLink(i,i));}}
return A.join('');

//generic methods
function generateTable(tbId,colSchema,dataAry){
var A=[];
for(var i=0;i<dataAry.length;i++){
A.push('<tr '+((i&1)?'':'class="NormalGridItem"')+' 
    onmouseout="style.backgroundColor=\'\';" >');
//insert cell by order that define in your schema and match with the result.
$(A.join('')).insertAfter('#'+tbId+' tr:first');

//construct an object array which map your schema and return 
//result header,if the schema field is not found in result, it will be nothing.
function jstrToObjAry(jsonStr){
var jAry=JSON.parse(jsonStr);
var oAry=[];
for(var i=1;i<jAry.length;i++){oAry.push(new objType(jAry,i));}
return oAry;
function objType(ary,n){for(var x=0;x<ary[0].length;x++){

How it Works in the Page

As I metioned on the top, the page must be Jpage and use this control.

In aspx page it should looks like this normally:

<%@ Register TagPrefix="uc1" TagName="JgridCtl" Src="../UserControls/JgridCtl.ascx" %>
<script type="text/javascript" src="<%= PathToPageAjaxScript%>"></script>
<script type="text/javascript">
var pgData=<%=pageData%>;
var res=<%=resource%>;
<form id="Form1" method="post" defaultfocus="btnSearch" runat="server">
<uc1:JgridCtl ID="JgridCtl1" runat="server">
<table id="tbLocation" class="simpleTable" 

<tr class="NormalGridHeader">
<td id="idxCol"></td>
<td class="hideCol" id="IdCol">Id</td>
<td><asp:label id="ColCompany" runat="server"></asp:label></td>
<td><asp:label id="ColLocation" runat="server"></asp:label></td>
<td><asp:label id="ColType" runat="server"></asp:label></td>
<td><asp:label id="ColContact" runat="server"></asp:label></td>
<td><asp:label id="ColAddress" runat="server"></asp:label></td>

As you see, page loads the Jgrid control and define your table template with column headers.

In aspx.cs

//inherit from Jpage
public class Locations : Jpage
    //inital data for javascript
    #region Properties
    public string pageData { get; private set; }
    public string resource { get; private set; }
    public string PathToPageAjaxScript { get { 
        return Page.ResolveUrl("../YourPath/Locations.js") + 
        "?version=" + Config.Version; } }
    private void Page_Load(object sender, System.EventArgs e)
        //usually remove the viewstate to improve peformance
        if ( !Page.IsPostBack )
        //initial resource for javascript
        resource = serializer.Serialize(new{Edit = GetResource("[Edit]"),
            Del = GetResource("[Delete]")});
        //initial other variable for javascript
        pageData = serializer.Serialize(new{
        editLink = this.Request.ApplicationPath + 
            "/YourPath/EditLocation.aspx?{0}&RetPath=" + 

    #region Ajax methods
    //the Ajax methods must be protected with return as part one demo
    protected object getList() {
        var result = YourLogic.Locations.Lookup(ParamId("Type"),
            Param("Zip"), Param("Phone"), Param("Contact"), ParamId("PerPage"), 
        //consruct the result set, filter result from the collection type by 
        //LINC and convert it to JSON format string.
        //the anonymous type properties must map with the schema which defined
        //in the javascript.
        //after the serilaize, the result looks like 
        //[["ID","Name","Company".....],["195","mylocation","my company"...],[....],.....]
        var list = result.OfType<YourLogic.Location>().Select(i => new {
            i.ID, i.Name, i.Company,i.TypeDesc,i.Contact,
            Address=i.Address.FullAddressText }).ToList().ToDataTable().ToJsonString();
        //return an anonymouse type with result list and ammount number
        return new { total = result.VirtualRows, list };

ToDataTable() and ToJsonString() are extension methods you need:

public static DataTable ToDataTable<T>(this IList<T> data) {
    PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
    DataTable table = new DataTable();
    foreach (PropertyDescriptor prop in properties)
            (prop.PropertyType.IsGenericType && 
            prop.PropertyType.GetGenericTypeDefinition() == 
            typeof(Nullable<>)) ? Nullable.GetUnderlyingType(
            prop.PropertyType) : prop.PropertyType);

        foreach (T item in data) {
        DataRow row = table.NewRow();
        foreach (PropertyDescriptor prop in properties)
        row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
    return table;
//we use Newtonsoft library here, you can write your own.
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
public static string ToJsonString(this DataTable table)
    JArray jsItems = new JArray();
    // first row should be a Header containing field names
    JArray jsItem = new JArray();
    for (int i = 0; i < table.Columns.Count; i++)
        for (int r = 0; r < table.Rows.Count; r++) {
            jsItem = new JArray();
            for (int c = 0; c < table.Columns.Count; c++)
    return jsItems.ToString(Formatting.None);

In page JS File

var cmdContent=null;
//page level ready function
function JgridReady(){
//html table id in the template
//the schema need match the order in the grid and the result header

//construct the parameter
function getParameter(){

//customize the table after it was created
function customTable(tbId){
var startRow=(currentPg-1)*currentPerPage+1;
var idxIdx=tdIdx('idxCol');
var idIdx=tdIdx('IdCol');
var rows=$('#'+TB+' tr:gt(0)');
var R=null;
for(var i=0;i<rows.length;i++){
//add the row index in every row, actually you can make it in the user control
//add a link command in every row
//add a command dynamically in every row, if command link name 'Delete',
//it will create javascript call tbLocationDelete(row) dynamically.
    var funcName=TB+$(this).attr('name');window[funcName]($(this).closest('tr'))

Now, you can see it is easy to implement this grid, 3 steps only:

  1. import it in aspx and define a template with html table for structure and header.
  2. create protected Ajax methods with return in code behind.
  3. assign table id, schema in JS file, provide a getParameter() to construct parameters and customTable() method to customize table.

You can improve this solution as you like, it will be more powerful. In next part I will provide another solution to export your ajax grid data to Excel file.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Software Developer
Canada Canada
No Biography provided

You may also be interested in...


Comments and Discussions

Discussions posted for the Published version of this article. Posting a message here will take you to the publicly available article in order to continue your conversation in public.
QuestionGood Article.....Can you please upload the code for this article Pin
Prakashius_Home29-Jun-12 1:49
memberPrakashius_Home29-Jun-12 1:49 
QuestionYou need a download... Pin
Dewey5-Oct-11 8:31
memberDewey5-Oct-11 8:31 
QuestionNeeds formatting Pin
Richard MacCutchan4-Oct-11 5:53
mvpRichard MacCutchan4-Oct-11 5:53 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.170713.1 | Last Updated 4 Oct 2011
Article Copyright 2011 by kennysun
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid