Creating a Dynamic Grid with Batch Editing
Environment
Product | Grid for Progress® Telerik® UI for ASP.NET Core |
Description
How can I create a dynamic Telerik UI Grid in ASP.NET Core that uses batch editing?
Solution
The suggested approach demonstrates how to bind a DataTable
to a Telerik UI Grid and enable the Batch editing.
- Populate the Grid columns based on the available
Model.Columns
.Model.Columns
is the collection of columns of the createdDataTable
. - Set the column title by using the
Caption
property of theDataColumn
. - Activate the Batch editing:
.DataSource(dataSource => dataSource.Ajax().Batch(true))
. - Define the
Model
in theDataSource
configuration by using theColumnName
andDataType
properties of theDataColumns
. Also, it is important to set the ModelId
to match theDataTable
PrimaryKey
. - On the controller side, obtain each of the modified DataTable records by using the
[Bind(Prefix = "models")]
attribute.
@model System.Data.DataTable
@(Html.Kendo().Grid<dynamic>()
.Name("Grid")
.Columns(columns =>
{
foreach (System.Data.DataColumn dcolumn in Model.Columns)
{
switch (dcolumn.DataType.ToString())
{
case "System.Int16":
case "System.Int32":
case "System.Int64":
columns.Bound(dcolumn.ColumnName).Title(dcolumn.Caption).EditorTemplateName("Integer");
break;
case "System.Decimal":
case "System.Double":
case "System.Float":
columns.Bound(dcolumn.ColumnName).Title(dcolumn.Caption).EditorTemplateName("Number");
break;
case "System.String":
columns.Bound(dcolumn.ColumnName).Title(dcolumn.Caption).EditorTemplateName("String");
break;
case "System.Byte":
case "System.Boolean":
columns.Bound(dcolumn.ColumnName).Title(dcolumn.Caption).EditorTemplateName("Boolean");
break;
case "System.DateTime":
columns.Bound(dcolumn.ColumnName).Title(dcolumn.Caption).Format("{0:d}").EditorTemplateName("Date");
break;
default:
columns.Bound(dcolumn.ColumnName).Title(dcolumn.Caption).EditorTemplateName("String");
break;
}
}
columns.Command(command => command.Destroy());
})
.ToolBar(toolbar => {
toolbar.Create();
toolbar.Save();
})
.Pageable()
.Sortable()
.Editable(editable => editable.Mode(GridEditMode.InCell))
.Filterable()
.Groupable()
.DataSource(dataSource => dataSource
.Ajax()
.Batch(true)
.Model(model =>
{
var id = Model.PrimaryKey[0].ColumnName;
model.Id(id);
foreach (System.Data.DataColumn column in Model.Columns)
{
var field = model.Field(column.ColumnName, column.DataType);
if (column.ColumnName == id) {
field.Editable(false);
}
}
})
.Create(create => create.Action("Customers_Create", "DynamicBatchEditing"))
.Read(read => read.Action("Customers_Read", "DynamicBatchEditing"))
.Update(update => update.Action("Customers_Update", "DynamicBatchEditing"))
.Destroy(destroy => destroy.Action("Customers_Destroy", "DynamicBatchEditing"))
)
)
public class DynamicBatchEditingController : Controller
{
public static DataTable db = new DataTable();
public ActionResult DynamicBatchEditing()
{
db = GetDataTable(50);
return View(db);
}
private DataTable GetDataTable(int howMany)
{
DataTable dt = GetDataTableColumns();
for (int i = 0; i < howMany; i++)
{
int index = i + 1;
DataRow row = dt.NewRow();
row["OrderID"] = index;
row["OrderDate"] = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, 0, 0, 0).AddHours(index);
row["Freight"] = index * 0.1 + index * 0.01;
row["ShipName"] = "Name " + index;
row["ShipCity"] = "City " + index;
row["ShipCountry"] = "Country " + index;
dt.Rows.Add(row);
}
return dt;
}
public ActionResult Customers_Read([DataSourceRequest] DataSourceRequest request)
{
return Json(db.ToDataSourceResult(request));
}
public ActionResult Customers_Create([DataSourceRequest] DataSourceRequest request, [Bind(Prefix = "models")] IFormCollection models)
{
DataTable editedItemsTable = GetDataTableColumns(); // Gather the table columns.
for (int x = 0; x < models.Count; x++) // Traverse through each of the models.
{
if (models.Keys.Contains("models[" + x + "].OrderID")) // Assert whether the models' keys contains the current record's primary key.
{
int index = x; // Get the current index.
DataRow row = editedItemsTable.NewRow(); // Create a new DataRow instance.
// Alter the fields.
row["OrderID"] = new Random().Next(models.Count, Int32.MaxValue);
row["OrderDate"] = models["models[" + index + "].OrderDate"][0];
row["Freight"] = models["models[" + index + "].Freight"][0];
row["ShipName"] = models["models[" + index + "].ShipName"][0];
row["ShipCity"] = models["models[" + index + "].ShipCity"][0];
row["ShipCountry"] = models["models[" + index + "].ShipCountry"][0];
// Add the newly edited row.
editedItemsTable.Rows.Add(row);
}
}
db.Merge(editedItemsTable); // Merge the changes to the existing DataTable.
return Json(editedItemsTable.ToDataSourceResult(request));
}
public ActionResult Customers_Update([DataSourceRequest] DataSourceRequest request, [Bind(Prefix = "models")] IFormCollection models)
{
DataTable editedItemsTable = GetDataTableColumns(); // Gather the table columns.
for (int x = 0; x < models.Count; x++) // Traverse through each of the models.
{
if (models.Keys.Contains("models[" + x + "].OrderID"))
{
int index = x; // Get the current index.
DataRow row = editedItemsTable.NewRow(); // Assert whether the models' keys contains the current record's primary key.
// Alter the fields.
row["OrderID"] = Int32.Parse(models["models[" + index + "].OrderID"][0]);
row["OrderDate"] = models["models[" + index + "].OrderDate"][0];
row["Freight"] = models["models[" + index + "].Freight"][0];
row["ShipName"] = models["models[" + index + "].ShipName"][0];
row["ShipCity"] = models["models[" + index + "].ShipCity"][0];
row["ShipCountry"] = models["models[" + index + "].ShipCountry"][0];
// Add the newly edited row.
editedItemsTable.Rows.Add(row);
}
}
db.Merge(editedItemsTable); // Merge the changes to the existing DataTable.
return Json(editedItemsTable.ToDataSourceResult(request));
}
public ActionResult Customers_Destroy([DataSourceRequest] DataSourceRequest request, [Bind(Prefix = "models")] IFormCollection models)
{
for (int i = 0; i < models.Count; i++) // Traverse through each of the models.
{
var primaryKey = db.PrimaryKey[0].ToString(); // Obtain the primary key field name.
if (models.Keys.Contains($"models[{i}].{primaryKey}")) // Assert whether the currently traversed model's keys contains the primary key field.
{
var itemToBeRemoved = models[$"models[{i}].{primaryKey}"][0]; // Obtain the to-be-removed row index from the primary key field.
foreach (DataRow row in db.Rows) // Traverse through each of the DataTable rows.
{
if (row[db.PrimaryKey[0]].ToString() == itemToBeRemoved) // Assert whether the current row's primary key value is equal to the to-be-removed row index.
{
db.Rows.Remove(row); // Remove the row.
break;
}
}
}
}
return Json(db.ToDataSourceResult(request));
}
private DataTable GetDataTableColumns()
{
DataTable dt = new DataTable();
dt.Columns.Add(new DataColumn("OrderID", typeof(int)));
dt.Columns.Add(new DataColumn("OrderDate", typeof(DateTime)));
dt.Columns.Add(new DataColumn("Freight", typeof(decimal)));
dt.Columns.Add(new DataColumn("ShipName", typeof(string)));
dt.Columns.Add(new DataColumn("ShipCity", typeof(string)));
dt.Columns.Add(new DataColumn("ShipCountry", typeof(string)));
dt.PrimaryKey = new DataColumn[] { dt.Columns["OrderID"] };
return dt;
}
}
For a complete and autonomous example of the aforementioned approach, refer to the following GitHub example.