In my previous article of Ajax enabled grid using ICallbackEventHandler I outline the creation of a grid with the following operations
- Sort the grid in ascending or in descending order by clicking on the arrows next to a column name.
- Change pages of the grid.
- Change page length of the grid.
In this article we will discuss editing the grid with the principal goal of doubleclicking on a grid cell to enable editing of that cell then edit the content of the cell and finally update server side data without refreshing the page.
The key advantages of this grid are as follows
- Data will be bind to grid only once, i.e. on page load.
- Only modified data goes to server to update the grid.
The basic UI will contain one Gridview and one update button. We will bind data to grid on page load.
- Simply copy paste following code in the <form> tag of the page
<div id=”Gridview”>
<asp:GridView EnableViewState=”false” runat=”server” id=”_grid” OnRowDataBound=”_grid_RowDataBound”>
</asp:GridView>
<span id =”ServerMsg”></span>
</div>
<br />
<input type=button value=”Update” onclick=”javascript: JSUpdateTable ();” />
<script language=”javascript”>
function UpdateGrid(args)
{
<%= ClientScript.GetCallbackEventReference(this,”args”, “ShowResult”, null) %>;
}
</script>
<asp:GridView EnableViewState=”false” runat=”server” id=”_grid” OnRowDataBound=”_grid_RowDataBound”>
</asp:GridView>
<span id =”ServerMsg”></span>
</div>
<br />
<input type=button value=”Update” onclick=”javascript: JSUpdateTable ();” />
<script language=”javascript”>
function UpdateGrid(args)
{
<%= ClientScript.GetCallbackEventReference(this,”args”, “ShowResult”, null) %>;
}
</script>
We have activated RowDataBound event of the grid.
- We will maintain a datatable, so that we can avoid fetching data from database. We will assume that we have a datatable and we define get and set properties for the table as follows.
public DataTable _sampleData
{
get {
DataTable dt = (DataTable) Session["DataTable"];
if(dt == null)
{
dt = new DataTable();
dt.Columns.Add(new DataColumn(“Contact Name”,typeof(string)));
dt.Columns.Add(new DataColumn(“Company Name”, typeof(string)));
dt.Columns.Add(new DataColumn(“City”, typeof(string)));
dt.Columns.Add(new DataColumn(“Country”, typeof(string)));
{
get {
DataTable dt = (DataTable) Session["DataTable"];
if(dt == null)
{
dt = new DataTable();
dt.Columns.Add(new DataColumn(“Contact Name”,typeof(string)));
dt.Columns.Add(new DataColumn(“Company Name”, typeof(string)));
dt.Columns.Add(new DataColumn(“City”, typeof(string)));
dt.Columns.Add(new DataColumn(“Country”, typeof(string)));
dt.Rows.Add(new object[] { “Maria Anders” ,”Alfreds Futterkiste”,”Berlin”,”Germany”});
dt.Rows.Add(new object[] { “Ana Trujillo” ,”Emparedados y helados “,”México D.F.”,”Mexico”});
dt.Rows.Add(new object[] { “Antonio Moreno”, “Antonio Moreno Taquería”, “México D.F.”,”Mexico” });
Session["DataTable"] = dt;
}
return dt;
}
set
{
Session["DataTable"] = value;
}
}
dt.Rows.Add(new object[] { “Ana Trujillo” ,”Emparedados y helados “,”México D.F.”,”Mexico”});
dt.Rows.Add(new object[] { “Antonio Moreno”, “Antonio Moreno Taquería”, “México D.F.”,”Mexico” });
Session["DataTable"] = dt;
}
return dt;
}
set
{
Session["DataTable"] = value;
}
}
We can write a function which will return a datatable, and the get property will simply return that table. We have used a session variable instead of viewstate to store the table; this is because we need to update data on the server side, if we use viewstate we would need to do post back of the page.
To bind this table to the grid we can simply set the datasource of the grid to the datatabe :_grid.DataSource = _sampleData;
And to set new data table we will add _sampleData = _tempTable;
And to set new data table we will add _sampleData = _tempTable;
Here _tempTable is the updated table after updating the grid on client side.
- We will observe the typical ICallbackEventHandler procedure and add the following points on server side page, i.e. in c# code.
- Inherit page class by ICallbackEventHandler interface : public partial class Default : System.Web.UI.Page , ICallbackEventHandler
- Add RaiseCallbackEvent(string eventArgument) and GetCallbackResult() as follows :
public void RaiseCallbackEvent(string eventArgument)
{
string[] args = eventArgument.Split(‘$’);
if (args[0] == “updateTable”) updateTable(args[1]);
}
{
string[] args = eventArgument.Split(‘$’);
if (args[0] == “updateTable”) updateTable(args[1]);
}
public string GetCallbackResult()
{
return result;
}
{
return result;
}
The result is a global variable declared on the page.
We are following the same convention for RaiseCallbackEvent(string eventArgument)which we have used in my last article ( Ajax enabled grid using ICallbackEventHandler )
- To make the cell editable on by a double-click we need to add javascript which will convert the cell in to textbox or a dropdownlist in such way that we can keep track of each updated cell.
We can view a grid and and datatable as a two dimentional arrays with any cell being referenced by a row,column combination (i.e. row[i][j]).
As we have discussed earlier; we will look at the grid as a two dimentional array. Thus we will maintain unique id for each cell so that cell id will give the position of that cell in the datatable.
Here, understand that grid data is an exact copy of the datatable so row[i][j] in datatable will match with row[i][j] of grid.
Here, understand that grid data is an exact copy of the datatable so row[i][j] in datatable will match with row[i][j] of grid.
- In step 1 we activated RowDataBound event of the grid. In this step we will write the code for RowDataBound event.
Define _rowNumber as global variable for same page.
int _rowNumber = 0;
int _rowNumber = 0;
protected void _grid_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
for (int i = 0; i < e.Row.Cells.Count; i++)
{
e.Row.Cells[i].Attributes.Add(“ondblclick”, ”javascript:MakeCellEditable(this);”);
e.R
ow.Cells[i].Attributes.Add(“id”, _rowNumber + “_” + i);
}
_rowNumber += 1;
}
}
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
for (int i = 0; i < e.Row.Cells.Count; i++)
{
e.Row.Cells[i].Attributes.Add(“ondblclick”, ”javascript:MakeCellEditable(this);”);
e.R
ow.Cells[i].Attributes.Add(“id”, _rowNumber + “_” + i);
}
_rowNumber += 1;
}
}
To make cell editable we have add:
e.Row.Cells[i].Attributes.Add(“ondblclick”,”javascript:MakeCellEditable(this);”);
e.Row.Cells[i].Attributes.Add(“ondblclick”,”javascript:MakeCellEditable(this);”);
MakeCellEditable(this) will write this JavaScript function in next step.
To identify each cell as unique cell and to mach it with corrosponding datatable entry, we will give id to each cell in such a way that it will follow row[i][j] structure.
i.e. e.Row.Cells[i].Attributes.Add(“id”, _rowNumber + “_” + i);
i.e. e.Row.Cells[i].Attributes.Add(“id”, _rowNumber + “_” + i);
And we are increasing row number each time. Observe the way we have given id, we will get [i][j] position just by spliting the is on “_”.
- To make cell editable we will write following function in JavaScript
function MakeCellEditable(obj)
{
if(!window.document.getElementById(obj.id + “_input”))
{
obj.innerHTML = “<input id=”+ obj.id + “_input” + ” type=text value=’” + obj.innerText + “‘/>”
}
window.document.getElementById(obj.id + “_input”).focus();
}
{
if(!window.document.getElementById(obj.id + “_input”))
{
obj.innerHTML = “<input id=”+ obj.id + “_input” + ” type=text value=’” + obj.innerText + “‘/>”
}
window.document.getElementById(obj.id + “_input”).focus();
}
This function will convert the cell into text box and set focus in that text box. Check the way we have assinged theid to the text box (i.e.[i]_[j]_input obj is the cell)
//break//
- Up to this point we have made the cell editable – now we need to select all updated values and send them to server to update the datatable.
Onclick of the Update button has a javascript function named UpdateTable() (refer to step 1). This function is listed below:
function JSUpdateTable()
{
var ddl = window.document.getElementById(‘Gridview’);
var ddl1 = ddl.getElementsByTagName(‘input’);
var data = “”;
for(i = 0 ; i < ddl1.length ; i++)
{
ddlId[i] = ddl1[i].id; //ddlId is a global array in JS we will use it in step 9
if(i == 0 ) data = ddl1[i].id + “|” + ddl1[i].value;
else data = data + “~” + ddl1[i].id + “|” + ddl1[i].value;
}
UpdateGrid(‘updateTable$’+data);
}
{
var ddl = window.document.getElementById(‘Gridview’);
var ddl1 = ddl.getElementsByTagName(‘input’);
var data = “”;
for(i = 0 ; i < ddl1.length ; i++)
{
ddlId[i] = ddl1[i].id; //ddlId is a global array in JS we will use it in step 9
if(i == 0 ) data = ddl1[i].id + “|” + ddl1[i].value;
else data = data + “~” + ddl1[i].id + “|” + ddl1[i].value;
}
UpdateGrid(‘updateTable$’+data);
}
- The UpdateGrid function will call RaiseCallbackEvent(string eventArgument) on the server.
Recall step 3 where we defined RaiseCallbackEvent(string eventArgument) and used the updateTable function. On the updateTable is a server-side function which is responsible for updating the Datatable. The function will be as follows.
private void updateTable(string _data)
{
string[] _NewData = _data.Split(‘~’);
DataTable _tempTable = _sampleData;
for (int i = 0; i < _NewData.Length; i++)
{
string [] _changedTxt = _NewData[i].Split(‘|’);
string[] _rowCol = _changedTxt[0].Split(‘_’);
_tempTable.Rows[Convert.ToInt32(_rowCol[0])][Convert.ToInt32(_rowCol[1])] = _changedTxt[1];
}
_sampleData = _tempTable;
result = “SUCCESS”;
}
{
string[] _NewData = _data.Split(‘~’);
DataTable _tempTable = _sampleData;
for (int i = 0; i < _NewData.Length; i++)
{
string [] _changedTxt = _NewData[i].Split(‘|’);
string[] _rowCol = _changedTxt[0].Split(‘_’);
_tempTable.Rows[Convert.ToInt32(_rowCol[0])][Convert.ToInt32(_rowCol[1])] = _changedTxt[1];
}
_sampleData = _tempTable;
result = “SUCCESS”;
}
In step 7 we have seen the javascript function JSUpdateTable() and how we send updated data in the format of string.
For further understanding lets assume that we are sending data to the server and _data = “0_1_input|ABC~3_3_input|XYZ”. Now in the above function observe how we manipulate and parse _data.
result = “SUCCESS”; result is a global string.
After updating the DataTable on the server-side we will send result to client, and if result = “SUCCESS” we will know that the datatable has been updated successfully.
The GetCallbackResult() function (ref. step 3) will send result string to client.
- On the client-side we need one function which will automatically get called. In step one we have registered following function
function UpdateGrid(args)
{
<%= ClientScript.GetCallbackEventReference(this,”args”, “ShowResult”, null) %>;
}
(Please reffer my previouse AJAX Grid article for more details on this function)
{
<%= ClientScript.GetCallbackEventReference(this,”args”, “ShowResult”, null) %>;
}
(Please reffer my previouse AJAX Grid article for more details on this function)
ShowResult JavaScript function will get called automatically after the GetCallbackResult(), so now we will write this function.
var ddlId = new Array();//Elements are added in step 7
// This array contain ids of textboxes
function ShowResult(eventArgument ,context)
{
formObj = window.document;
if(eventArgument == “SUCCESS”)
{
for(j = 0 ; j < ddlId.length ; j++)
{
var ids = ddlId[j].split(“_”);
formObj.getElementById(ids[0] + “_” + ids[1]).innerHTML = formObj.getElementById(ddlId[j]).value;
}
document.getElementById(‘ServerMsg’).innerText = “Data has been updated Successfully…”;
}
}
// This array contain ids of textboxes
function ShowResult(eventArgument ,context)
{
formObj = window.document;
if(eventArgument == “SUCCESS”)
{
for(j = 0 ; j < ddlId.length ; j++)
{
var ids = ddlId[j].split(“_”);
formObj.getElementById(ids[0] + “_” + ids[1]).innerHTML = formObj.getElementById(ddlId[j]).value;
}
document.getElementById(‘ServerMsg’).innerText = “Data has been updated Successfully…”;
}
}
The above function is used only remove editable cells (i.e. to remove textboxes and to indicate that the server data has been updated)
- On page_load we bind the grid :
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
_grid.DataSource = _sampleData;
_grid.DataBind();
}
}
{
if (!IsPostBack)
{
_grid.DataSource = _sampleData;
_grid.DataBind();
}
}
Further Enhancements
For editing the grid some points need to be considered. We have discussed only about using text boxes for editing but we could also use a dropdownlist or other controls.
If we are using paging and sorting updating a row in the datatable causes a problem for cell referencing. In this case we can add a column to the datatable which corresponds to table row, so if we sort the table and can still maintain the row number (i.e [i] in row[i][j] ). This column will be hidden in the grid so that we can use it for adding and deleting the the data as well.
Code
The full code can be downloaded here
The code contains two aspx pages
- EditGridDemo.aspx : This page contains the code in this article.
- AjaxifiedGrid.aspx: This page contains the code for fully ajaxified grid.
Comments
Post a Comment