In our grid (EditMode="Batch", InsertItemDisplay="Bottom", EditType="Cell", OpenEditingEvent="Click") we want to add a new row to the grid if the user clicks on any cell in the last row.
I made a function to call for OnBatchEditOpened. If it finds you are in the bottom row, it creates a new row below it by running batchManager.addNewRecord(masterTable)
That works, which triggers my OnRowCreated function, which I want. In there, it runs batchManager.changeCellValue for multiple columns in the new row to initialize their values.
However, each of those initializing statements (done via changeCellValue) triggers my original function for OnBatchEditOpened, creating a loop. I try to avoid it by creating temp variables outside the functions that skip that function if OnRowCreated is running. It kind of works. But even so, afterwards, the original cell is no longer in edit mode, which we want.
So now in the original call to OnBatchEditOpened, I'm storing a temp variable of the original cell, which I then try to re-open via batchManager.openCellForEdit(cellTemp), but it doesn't always work. And even when it does, the function now calls itself because a cell is being opened!
Ugh!
All that said, I must be going about this the wrong way. So back to the original issue...
Without going through dodgy javascript acrobatics, how can I click on a cell to edit it, but if it's in the bottom row, create a new row below it, yet keep (or resume?) the original cell in edit mode. There must be an easier way than what I'm doing to avoid loops, temp vars, and with robust code, but I've no clue what it is. Please help.
7 Answers, 1 is accepted
I kind of got around the situation described above by taking all the changeCellValue calls out of my OnRowCreated function. That way OnBatchEditOpened is no longer called. To instead set the values in OnRowCreated, I have this code...
cell = newItem.get_cell(
'UnitPrice'
);
cell.innerHTML =
"<div>0.0000</div>"
cell = newItem.get_cell(
'PurchaseOrderDetailAmount'
);
cell.innerHTML =
"<div>0.00</div>"
cell = newItem.get_cell(
'PrintOnPurchaseOrder'
);
cell.innerHTML =
"<div><input id='chkPrintRead' onclick='changeEditor(this);' type='checkbox' checked='True'></div>"
;
That seems really hokey, especially since I now have to maintain formatting in 2 different places (both grid and in this function) but by doing so, I'm able to avoid using temp vars to exit OnBatchEditOpened when OnRowCreated is running, and I get no funky errors later on.
Another thing I had to add, is apparently when a new row is added, OnBatchEditOpened is called again. (Must want to open up a cell in the new row?) So now in that function, just before I call addNewRecord, I assign an outer var of cellTemp to args.get_cell(). Now when OnBatchEditOpened is called, it checks if cellTemp has a value, and if so, runs this code...
if
(cellTemp) {
// reopen cell we were wanting to edit originally
setTimeout(
function
() {
batchManager.openCellForEdit(cellTemp);
cellTemp =
null
;
}, 100);
return
false
;
}
Without the time delay, it doesn't work, and I get funky errors later. So while all this seems to work, I feel like I'm breaking Telerik rules and there should be an better way, which will also make the code more manageable.
Is there an easier way? Also, I'm wondering if assigning to innerHTML in OnRowCreated is bad, because in those cells, there are no longer little red triangles in the upper left to indicate a change has been made, as there was with changeCellValue. Am I setting myself up for problems later on?
Yes, you are correct. You should only use the built-in editing API when executing Batch related logic. Otherwise, you are setting yourself for problems later on, as you've providently stated.
I've created a sample RadGrid web site to demonstrate how you can achieve this requirement. The columns have their DefaultInsertValue properties set. Please run the attached application and let me know if it helps you.
Regards,
Eyup
Telerik
That's definitely cleaner than my code! Thanks for the example. I modified it a bit to mimic mine (and copy-pasted below since I can't attach a zip file) to show 3 problems...
1) If you click on the bottom row it works, but if you click on the new bottom row, it doesn't create another row, but it should.
2) The checkbox shows "true" rather than a checkbox. (That's part of why I used innerHMTL in my earlier post, but there must be a better solution.)
3) We also need it to populate with 2 blank rows if there's no data. So on the server-side, if you comment out the code that populates the dataset, my gridCreated code will execute the IF block. It creates 2 rows, but doesn't give default values. (I could create the 2 blank rows server-side, but that would require maintaining 2 places of default values -- on the grid and in code. But if that's the only way, then so be it.)
Thanks for your help, and look forward to your answers.
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="RadGridEditBatchLastRowLogic.aspx.cs" Inherits="RadGridEditBatchLastRowLogic" %>
<!DOCTYPE html>
<
html
xmlns
=
"http://www.w3.org/1999/xhtml"
>
<
head
runat
=
"server"
>
<
title
></
title
>
</
head
>
<
body
>
<
form
id
=
"form1"
runat
=
"server"
>
<
telerik:RadScriptManager
ID
=
"RadScriptManager1"
runat
=
"server"
>
<
Scripts
>
<
asp:ScriptReference
Assembly
=
"Telerik.Web.UI"
Name
=
"Telerik.Web.UI.Common.Core.js"
/>
<
asp:ScriptReference
Assembly
=
"Telerik.Web.UI"
Name
=
"Telerik.Web.UI.Common.jQuery.js"
/>
<
asp:ScriptReference
Assembly
=
"Telerik.Web.UI"
Name
=
"Telerik.Web.UI.Common.jQueryInclude.js"
/>
</
Scripts
>
</
telerik:RadScriptManager
>
<
script
type
=
"text/javascript"
>
//Put your JavaScript code here.
function gridCreated(sender, args) {
var masterTable = sender.get_masterTableView();
var rows = masterTable.get_dataItems();
if (rows.length == 0) {
var batMan = sender.get_batchEditingManager();
batMan.addNewRecord(masterTable);
batMan.addNewRecord(masterTable);
}
}
function batchEditOpened(sender, args) {
var batMan = sender.get_batchEditingManager();
var tableView = args.get_tableView();
var items = tableView.get_dataItems();
var item = args.get_row().control;
if (items.length == (item.get_itemIndex() + 1)) {
setTimeout(function () {
batMan.addNewRecord(tableView);
batMan.openCellForEdit(args.get_cell());
}, 10);
}
}
</
script
>
<
telerik:RadAjaxManager
ID
=
"RadAjaxManager1"
runat
=
"server"
>
</
telerik:RadAjaxManager
>
<
telerik:RadGrid
ID
=
"RadGrid1"
runat
=
"server"
AllowPaging
=
"False"
CellSpacing
=
"0"
GridLines
=
"None"
Width
=
"800px"
OnNeedDataSource
=
"RadGrid1_NeedDataSource"
>
<
ClientSettings AllowKeyboardNavigation="true"
>
<
ClientEvents
OnBatchEditOpened
=
"batchEditOpened"
OnGridCreated
=
"gridCreated"
/>
</
ClientSettings
>
<
MasterTableView
AutoGenerateColumns
=
"False"
DataKeyNames
=
"PurchaseOrderDetailKey"
EditMode
=
"Batch"
InsertItemDisplay
=
"Bottom"
CommandItemDisplay
=
"Top"
>
<
BatchEditingSettings
EditType
=
"Cell"
OpenEditingEvent
=
"Click"
/>
<
Columns
>
<
telerik:GridNumericColumn
DataField
=
"PurchaseOrderDetailKey"
HeaderText
=
"PurchaseOrderDetailKey"
UniqueName
=
"PurchaseOrderDetailKey"
DataType
=
"System.Int32"
Visible
=
"False"
ReadOnly
=
"True"
>
</
telerik:GridNumericColumn
>
<
telerik:GridTemplateColumn
DataField
=
"PostToGeneralLedger"
HeaderText
=
"Post"
UniqueName
=
"PostToGeneralLedger"
DataType
=
"System.Boolean"
DefaultInsertValue
=
"true"
>
<
HeaderStyle
Width
=
"40px"
/>
<
ItemStyle
Width
=
"40px"
/>
<
ItemTemplate
>
<
input
id
=
"chkPost"
type
=
"checkbox"
checked='<%# Eval("PostToGeneralLedger") %>' onclick="changeEditor(this);" />
</
ItemTemplate
>
<
EditItemTemplate
>
<
asp:CheckBox
ID
=
"chkPost"
runat
=
"server"
Checked='<%# Bind("PostToGeneralLedger") %>' />
</
EditItemTemplate
>
</
telerik:GridTemplateColumn
>
<
telerik:GridTemplateColumn
DataField
=
"UnitPrice"
HeaderText
=
"UnitPrice"
UniqueName
=
"UnitPrice"
DataType
=
"System.Double"
DefaultInsertValue
=
"0"
>
<
ItemTemplate
>
<
asp:Label
ID
=
"lblUnitPrice"
runat
=
"server"
Text='<%# Eval("UnitPrice") %>'>
</
asp:Label
>
</
ItemTemplate
>
<
EditItemTemplate
>
<
telerik:RadNumericTextBox
ID
=
"txtUnitPrice"
runat
=
"server"
DataType
=
"System.Decimal"
MaxLength
=
"23"
Width
=
"100%"
IncrementSettings-InterceptArrowKeys
=
"false"
Culture
=
"English (United States)"
DbValue='<%# Bind("UnitPrice") %>' Type="Number" NumberFormat-DecimalDigits="4" />
</
EditItemTemplate
>
</
telerik:GridTemplateColumn
>
<
telerik:GridTemplateColumn
DataField
=
"UnitDescription"
UniqueName
=
"UnitDescription"
HeaderText
=
"Unit Desc"
DataType
=
"System.String"
DefaultInsertValue
=
"my default"
>
<
ItemTemplate
>
<
asp:Label
ID
=
"lblUnitDescription"
runat
=
"server"
Text='<%# Eval("UnitDescription") %>'>
</
asp:Label
>
</
ItemTemplate
>
<
EditItemTemplate
>
<
telerik:RadTextBox
ID
=
"txtUnitDescription"
runat
=
"server"
MaxLength
=
"10"
Width
=
"100%"
Text='<%# Bind("UnitDescription") %>' >
</
telerik:RadTextBox
>
</
EditItemTemplate
>
</
telerik:GridTemplateColumn
>
</
Columns
>
</
MasterTableView
>
</
telerik:RadGrid
>
</
form
>
</
body
>
</
html
>
using
System;
using
System.Collections.Generic;
using
System.Data;
using
System.Linq;
using
System.Web;
using
System.Web.UI;
using
System.Web.UI.WebControls;
using
Telerik.Web.UI;
public
partial
class
RadGridEditBatchLastRowLogic : System.Web.UI.Page
{
protected
void
Page_Load(
object
sender, EventArgs e)
{
}
protected
void
RadGrid1_NeedDataSource(
object
sender, GridNeedDataSourceEventArgs e)
{
RadGrid1.DataSource = GetGridSource();
}
private
DataTable GetGridSource()
{
DataTable dataTable =
new
DataTable();
DataColumn column =
new
DataColumn();
column.DataType = Type.GetType(
"System.Int32"
);
column.ColumnName =
"PurchaseOrderDetailKey"
;
dataTable.Columns.Add(column);
column =
new
DataColumn();
column.DataType = Type.GetType(
"System.Boolean"
);
column.ColumnName =
"PostToGeneralLedger"
;
dataTable.Columns.Add(column);
column =
new
DataColumn();
column.DataType = Type.GetType(
"System.Decimal"
);
column.ColumnName =
"UnitPrice"
;
dataTable.Columns.Add(column);
column =
new
DataColumn();
column.DataType = Type.GetType(
"System.String"
);
column.ColumnName =
"UnitDescription"
;
dataTable.Columns.Add(column);
DataColumn[] PrimaryKeyColumns =
new
DataColumn[1];
PrimaryKeyColumns[0] = dataTable.Columns[
"PurchaseOrderDetailKey"
];
dataTable.PrimaryKey = PrimaryKeyColumns;
for
(
int
i = 0; i <= 5; i++)
{
DataRow row = dataTable.NewRow();
row[
"PurchaseOrderDetailKey"
] = i + 1;
row[
"PostToGeneralLedger"
] =
true
;
row[
"UnitPrice"
] = (i + 1) + (i + 1) * 0.1 + (i + 1) * 0.01;
row[
"UnitDescription"
] =
"Name "
+ (i + 1);
dataTable.Rows.Add(row);
}
return
dataTable;
}
}
Also, I now get funky errors at times when navigating the grid. But those errors go away if I remove the DefaultInsertValues on my 3 columns. Does DefaultInsertValue not work with GridTemplateColumn?
I'm really confused how to proceed and our deadline is looming. Any help you can give soon would be very appreciated.
One more thing: If you put alert("batchEditOpened called"); as the first line in batchEditOpened and click on the bottom most row, you'll see that message pops up multiple times. This seems problematic to me, and goes back to the javascript acrobats I'm having to do, which is that calling addNewRecord within batchEditOpened calls itself.
I'm backing up and posting a support ticket with the various issues I've been posting on the forum as they're quite intertwined, with the hope that turnaround is faster, so never mind. But thanks for the example as it's a nice springboard.
I suggest that you continue the case in the new support ticket you've mentioned.
Regards,
Eyup
Telerik