This
article
shows you how to use ASP.NET AJAX PageMethods to perform Create, Read, Update
and Delete (CRUD) operations with an HTML table. Here HTML table acts as a
light-weight DataGrid.
Inorder to make PageMethods work, following things need to be done:
- ScriptManager should be added to your ASPX page.
- EnablePageMethods property of the ScriptManager should be set to true.
- System.Web.Services namespace should be added as reference on your codebehind class.
- Page
Methods on your code-behind should be decorated with [WebMethod] attribute.
First let us start with Read.
As
mentioned above, add a ScriptManager and set its 'EnablePageMethods'
property to true. Add an HTML button and an onclick handler to it, and
then add an HTML table with thead, tbody and tfoot. Since the HTML
table will be referenced from javascript, add id to the table and its
body. Here, only HTML tags/controls are used because, server side
controls cannot be referenced in PageMethods.
Your ASPX page should look something like this.
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1"
runat="server"
EnablePageMethods ="true"
></asp:ScriptManager>
<%--This click event
handles loading data from the database--%>
<input id="btn_load" type="button" value="Load" onclick
= "LoadData()"
/>
<br /><br />
<div>
<table style=" height: 100%; border: solid 1px #000" cellpadding="0" cellspacing="1" id="tbl_grid" border
= "1">
<thead style = "background-color: #666;
color: #fff">
<tr>
<td style="width: 100px;">
Column1
</td>
<td style="width: 500px;">
Column2
</td>
<td style="width: 150px;">
Edit
</td>
</tr>
</thead>
<tbody id="tbody_grid">
</tbody>
<tfoot>
<tr>
<td style="width: 100px;">
<input id="txt_addcol1" style
="width: 30px" type="text" />
</td>
<td style="width: 500px;">
<input id="txt_addcol2"
type="text" style ="width: 300px" />
</td>
<td style="width: 150px;">
<%--This click
event handles adding data to the database--%>
<input id="btn_add"
type="button"
onclick = "Add()" value="Add" />
</td>
</tr>
</tfoot>
</table>
</div>
</form>
</body>
Now
add your JavaScript function to load data from the database using
PageMethods. PageMethod call should always have a success handler (this
will be executed if the page method is executed successfully) and an
exception handler (this will be executed if an exception is thrown).
Say suppose we added 'GetData()' as the page method on the code behind,
our javascript will be PageMethods.GetData(SuccessHandler,
ExceptionHandler).
Just for understanding, I have named the success and exception handler
appropriately, you can name them as you wish. In case, the page methods takes parameters, you can add like PageMethods.GetData(param1, param2, SuccessHandler,
ExceptionHandler).
Page
methods should be decorated with [WebMethod] attribute and should be
declared as static. Its signature shoul look something like this:
[WebMethod]
public static string GetData()
Page method to return data to javascript.
public partial class AJAXGrid : System.Web.UI.Page
{
protected void Page_Load(object
sender, EventArgs e)
{
}
[WebMethod]
public static IEnumerable<MyEntity> GetData()
{
try
{
Data fetch part
should go here
// used List, as collections are serializable. See below for
MyEntity class
List<MyEntity>
MyEntities = new List<MyEntity>();
MyEntities.Add("1", "abc");
MyEntities.Add("2", "xyz");
MyEntities.Add("3", "pqr");
MyEntities.Add("4", "mno");
return MyEntities;
}
catch(Exception ex)
{
throw
ex;
}
}
}
MyEntity class
public class MyEntity
{
private string _Column1;
public string Column1
{
get { return _Column1; }
set {
_Column1 = value; }
}
private string _Column2;
public string Column2
{
get { return _Column2; }
set {
_Column2 = value; }
}
public
MyEntity(string sCol1, string
sCol2)
{
_Column1 = sCol1;
_Column2 = sCol2;
}
}
Javascript function that calls page method and populates the HTML table
<script type ="text/javascript"
language = "javascript ">
//Loading Data
// Handles
btn_load click event
function
LoadData() {
// If data was fetched successfully, SuccessHandler will be
called; else, ExceptionHandler
PageMethods.GetData(SuccessHandler,
ExceptionHandler);
// Incase parameters need to be passed to PageMethods, you
can do like this PageMethods.GetData(param1, param2, SuccessHandler, ExceptionHandler)
}
// After fetching
the data successfully
function
SuccessHandler(result) {
var
tbody = $get("tbody_grid");
// clear the
table
for (var j = tbody.rows.length; j > 0; j--) {
tbody.deleteRow(j - 1);
}
// populate
the table
for (var i = 0; i < result.length; i++) {
//two
columns fetched from database are sent as parameters
AddRow(result[i].Column1,
result[i].Column2);
}
return true;
}
// Edit and
Delete buttons are added to the rows
function
AddRow(col1, col2) {
var
tbody = $get("tbody_grid");
var row
= document.createElement("tr")
var td1
= document.createElement("td")
td1.innerText = col1;
var td2
= document.createElement("td");
td2.innerText = col2;
var td3
= document.createElement("td");
// add buttons
var
btnEdit = document.createElement('input');
btnEdit.setAttribute('type', 'button');
btnEdit.setAttribute('name', 'Edit');
btnEdit.setAttribute('value', 'Edit');
// first parentNode represents <td> and
the second represents <tr>
btnEdit.onclick = function() { Edit(this.parentNode.parentNode);
};
var btnDelete = document.createElement('input');
btnDelete.setAttribute('type', 'button');
btnDelete.setAttribute('name', 'Delete');
btnDelete.setAttribute('value', 'Delete');
btnDelete.onclick = function() { DeleteRow(this.parentNode.parentNode);
};
td3.appendChild(btnEdit);
td3.appendChild(btnDelete);
row.appendChild(td1);
row.appendChild(td2);
row.appendChild(td3);
tbody.appendChild(row);
}
// Handles exception
function
ExceptionHandler(result) {
}
After populating the HTML table

Javascript functions to handle Edit, Update, Delete and Insert:
Editing Data
// this function handles edit button click
function
Edit(row) {
var
col1 = row.childNodes[0].innerText;
var
col2 = row.childNodes[1].innerText;
// populates
values in textboxes and displays Update and Cancel buttons
var
editableRow = document.createElement("tr")
var td1
= document.createElement("td")
var
txtBox1 = document.createElement('input');
txtBox1.setAttribute('type', 'text');
txtBox1.setAttribute('name', 'col1');
txtBox1.setAttribute('value', col1);
txtBox1.setAttribute('width', 30);
td1.appendChild(txtBox1);
var td2
= document.createElement("td");
var
txtBox2 = document.createElement('input');
txtBox2.setAttribute('width', 300);
txtBox2.setAttribute('type', 'text');
txtBox2.setAttribute('name', 'col1');
txtBox2.setAttribute('value', col2);
td2.appendChild(txtBox2);
var td3
= document.createElement("td");
var
btnUpdate = document.createElement('input');
btnUpdate.setAttribute('type', 'button');
btnUpdate.setAttribute('name', 'Update');
btnUpdate.setAttribute('value', 'Update');
btnUpdate.onclick = function() { Update(this.parentNode.parentNode);
};
var
btnCancel = document.createElement('input');
btnCancel.setAttribute('type', 'button');
btnCancel.setAttribute('name', 'Cancel');
btnCancel.setAttribute('value', 'Cancel');
btnCancel.onclick = function() { Cancel(this.parentNode.parentNode);
};
td3.appendChild(btnUpdate);
td3.appendChild(btnCancel);
editableRow.appendChild(td1);
editableRow.appendChild(td2);
editableRow.appendChild(td3);
row.parentNode.replaceChild(editableRow, row);
}
After edit button click

Updating Data
// this function handles update button click
function
Update(row) {
// fetches
values entered in the textboxes
// first childNode represent <td> inside <tr> and second
childNode represents textbox
var
col1 = row.childNodes[0].childNodes[0].value;
var
col2 = row.childNodes[1].childNodes[0].value;
// values
sent to server
PageMethods.UpdateData(col1, col2,
UpdateSuccess(row), ExceptionHandler);
}
// After updating
the values successfully
function
UpdateSuccess(row) {
var
col1 = row.childNodes[0].childNodes[0].value;
var
col2 = row.childNodes[1].childNodes[0].value;
var
editableRow = document.createElement("tr")
var td1
= document.createElement("td")
td1.innerText = col1;
var td2
= document.createElement("td");
td2.innerText = col2;
var td3
= document.createElement("td");
var btnEdit
= document.createElement('input');
btnEdit.setAttribute('type', 'button');
btnEdit.setAttribute('name', 'Edit');
btnEdit.setAttribute('value', 'Edit');
btnEdit.onclick = function() { Edit(this.parentNode.parentNode);
};
var
btnDelete = document.createElement('input');
btnDelete.setAttribute('type', 'button');
btnDelete.setAttribute('name', 'Delete');
btnDelete.setAttribute('value', 'Delete');
btnDelete.onclick = function() { DeleteRow(this.parentNode.parentNode);
};
td3.appendChild(btnEdit);
td3.appendChild(btnDelete);
editableRow.appendChild(td1);
editableRow.appendChild(td2);
editableRow.appendChild(td3);
row.parentNode.replaceChild(editableRow,
row);
}
// this function handles cancel button click
function
Cancel(row) {
// values are
again populated in labels instead of textboxes
var
col1 = row.childNodes[0].childNodes[0].value;
var
col2 = row.childNodes[1].childNodes[0].value;
var
editableRow = document.createElement("tr")
var td1
= document.createElement("td")
td1.innerText = col1;
var td2
= document.createElement("td");
td2.innerText = col2;
var td3
= document.createElement("td");
var
btnEdit = document.createElement('input');
btnEdit.setAttribute('type', 'button');
btnEdit.setAttribute('name', 'Edit');
btnEdit.setAttribute('value', 'Edit');
btnEdit.onclick = function() { Edit(this.parentNode.parentNode);
};
var
btnDelete = document.createElement('input');
btnDelete.setAttribute('type', 'button');
btnDelete.setAttribute('name', 'Delete');
btnDelete.setAttribute('value', 'Delete');
btnDelete.onclick = function()
{ DeleteRow(this.parentNode.parentNode); };
td3.appendChild(btnEdit);
td3.appendChild(btnDelete);
editableRow.appendChild(td1);
editableRow.appendChild(td2);
editableRow.appendChild(td3);
row.parentNode.replaceChild(editableRow, row);
}
// this function handles 'add' button click
function
Add() {
var
col1 = $get("txt_addcol1").value;
var
col2 = $get("txt_addcol2").value;
// data sent
to the database
PageMethods.InsertData(col1, col2,
AddSuccess(col1, col2), ExceptionHandler);
}
// After adding
the data successfully
function
AddSuccess(col1, col2) {
// add the values
to the table
AddRow(col1, col2);
// clear the
textboxes in the footer
$get("txt_addcol1").value
= "";
$get("txt_addcol2").value
= "";
}
Deleting Data
// this function handles delete button click
function
DeleteRow(row) {
var
col1 = row.childNodes[0].innerText;
// delete
from the database
PageMethods.DeleteData(col1,
DeleteSuccess(row), ExceptionHandler);
}
function
DeleteSuccess(row) {
// delete the
row from the table
var
tbody = $get("tbody_grid");
tbody.removeChild(row);
}
</script>
Page methods to handle Edit, Update, Delete and Insert:
[WebMethod]
public static void
UpdateData(string sCol1, string sCol2)
{
try
{
Data update part should go here
}
catch(Exception ex)
{
throw
ex;
}
}
[WebMethod]
public static void
InsertData(string sCol1, string sCol2)
{
try
{
Data insert part should go here
}
catch(Exception ex)
{
throw
ex;
}
}
[WebMethod]
public static void
DeleteData(string sCol1)
{
try
{
Data delete
part should go here
}
catch (Exception ex)
{
throw
ex;
}
}
}
We can add paging and sorting too.
This code has been tested in IE7+, Firefox,
Chrome and Safari.
Some of the limitations in using ASP.NET
AJAX PageMethods:
1. We can't access asp.net server
controls (like TextBox control) in the WebMethod directly as we normally
access in the server side methods.
2. We can't access any
variable declared in the code behind.
Advantage:
PageMethods is a simple lightweight way to submit/fetch data to the
server using ASP.NET AJAX. This doesn't submit whole page data to the server
and also as opposed to the ASP.NET AJAX call back this doesn't even fire the
Page_Load and other Page events of the code behind page.