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:
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.
<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 style="width: 150px;">
Edit
</tr>
</thead>
<tbody id="tbody_grid">
</tbody>
<tfoot>
<input id="txt_addcol1" style ="width: 30px" type="text" />
<input id="txt_addcol2" type="text" style ="width: 300px" />
<%--This click event handles adding data to the database--%>
<input id="btn_add" type="button" onclick = "Add()" value="Add" />
</tfoot>
</table>
</div>
</form>
</body>
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;
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;
<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 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 txtBox1 = document.createElement('input');
txtBox1.setAttribute('type', 'text');
txtBox1.setAttribute('name', 'col1');
txtBox1.setAttribute('value', col1);
txtBox1.setAttribute('width', 30);
td1.appendChild(txtBox1);
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 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) {
// this function handles cancel button click
function Cancel(row) {
// values are again populated in labels instead of textboxes
// 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) {
// delete from the database
PageMethods.DeleteData(col1, DeleteSuccess(row), ExceptionHandler);
function DeleteSuccess(row) {
// delete the row from the table
tbody.removeChild(row);
</script>
Page methods to handle Edit, Update, Delete and Insert:
public static void UpdateData(string sCol1, string sCol2)
Data update part should go here
public static void InsertData(string sCol1, string sCol2)
Data insert part should go here
public static void DeleteData(string sCol1)
Data delete part should go here
catch (Exception ex)
We can add paging and sorting too.
This code has been tested in IE7+, Firefox, Chrome and Safari.
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.
Disclaimer The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.