Bharath M.
This is another post on the flexibility of Syncfusion Grid’s client-side functionality. Here are the steps involved:
Grid preparation
In this post, we are going to play with JSON functionalities of the grid. I chose the JSON mode for the grid and Excel-like editing to ensure that the grid is responding to JSON changes.
@{ Html.Grid("Grid1")
.ActionMode(ActionMode.JSON)
.AllowKeyboardNavigation(true)
.Column(column =>
{
column.Add(p => p.OrderID).HeaderText("Order ID").TextAlign(TextAlignment.Right).Width(100);
column.Add(p => p.CustomerID).HeaderText("Customer ID").Width(100);
column.Add(p => p.EmployeeID).Width(100);
column.Add(p => p.Freight).Width(100);
})
.ClientSideEvents(c =>
c.QueryCellInfo("Grid1QueryCell") // This adds the Data-bind attribute to a grid cell.
.OnActionComplete("ActionComplete")
.OnToolbarClickEvent("ToolbarClicked"))
.ToolBar(tools =>
{
tools.Add(GridToolBarItems.Update)
.Add(GridToolBarItems.Cancel);
})
.Mappers(m => m.SaveAction("BulkSave"))
.Editing(edit =>
{
edit.AllowEdit(true);
edit.EditMode(GridEditMode.ManualExcel);//Specify the grid edit mode.
edit.PrimaryKey(key => key.Add(p => p.OrderID));// Add primary key to primary key collections
}).Render();
}
Knockout’s ViewModel
Knockout.js is the better choice for dynamic UI updates without any glue-code or events. Here, the grid is bound with the “Editable Order” model from the server side. Since Knockout.js is model-based, we have to create a model on the client side also. The code for that is as follows:
function OrderViewModel(data) {
// Actual JSON from grid.
this.data = data;
// This is to detect changes in the model.
this.isDirty = ko.observable(false);
// Model properties.
this.OrderID = ko.observable().extend({ AutoUpdate: { "model": this, "name": "OrderID" } });
this.CustomerID = ko.observable().extend({ AutoUpdate: { "model": this, "name": "CustomerID" } });
this.EmployeeID = ko.observable().extend({ AutoUpdate: { "model": this, "name": "EmployeeID" } });
this.Freight = ko.observable().extend({ AutoUpdate: { "model": this, "name": "Freight" } });
}
// Created custom extender for auto-updating JSON data as well as the model.
ko.extenders.AutoUpdate = function (target, options) {
target(options.model.data[options.name]);
target.subscribe(function (newValue) {
// Notifying the model that it has been changed.
if (!options.model.isDirty())
options.model.isDirty(true);
// Updating changed values to original JSON data.
options.model.data[options.name] = newValue;
return target;
}
AutoUpdate is the custom extender for observables; it will take care of syncing a JSON data source between Knockout’s model and the grid’s data source.
We also need another model for storing the list of an OrderViewModel collection and binding it to a page.
function PageViewModel() {
this.dataSource = ko.observableArray([]);
}
Integrating the Grid and Knockout’s ViewModel
For the integration, we are going to write code for setting the data-bind attributes to a grid cell and binding the grid’s HTML elements to Knockout.js.
The QueryCellInfo code adding the data-bind attribute is as follows:
function Grid1QueryCell(sender, args) {
if (args.Column.Name) {
var currentData = "dataSource()[" + args.Element.parentNode.rowIndex + "].";
// Here we set the Knockout.js data-binding attribute.
$(args.Element).attr("data-bind", "text: " + currentData + args.Column.Name + ",css: {updatedCell : " + currentData + "isDirty}");
// text: is for updating cell values and
// css: is for notifying the user that cells have been updated.
}
}
For binding the model, we have to use the grid’s OnActionComplete event, since during initial rendering the grid didn’t have data in it. Let me show you the code:
// The jQuery ready event has been used to define the page view-model.
$(function () {
page = new PageViewModel();
// Knockout.js binding can be applied to the whole page here.
// ko.applyBindings(page);
});
// The grid's OnActionComplete event has been used to update Knockout’s data source.
function ActionComplete(grid, args) {
// Here we are setting the page data source.
page.dataSource(ko.syncJsMap(grid.get_jsonModeMgr().get_dataSource(), OrderViewModel));
// I'm going to enable all toolbar items.
grid.gridtoolbar.Enable_All();
// Clearing previous binding, if any.
ko.cleanNode($(grid.get_element()).find(".GridContent").children().get(0));
// Applying bindings to newly created content.
ko.applyBindings(page, $(grid.get_element()).find(".GridContent").children().get(0));
}
// We need to set updatedRecords on the ToolbarClicked event.
function ToolbarClicked(grid, args) {
// Getting the changed JSON data.
var koChanges = page.dataSource()
.filter(
function (obj) { return obj.isDirty(); });
// Marking the grid as Editing.
grid._edit._isEdit = true;
// Updating the changed records to the grid.
if (grid._edit._updatedRecords) {
// Merging the changes if there are any updates from the grid.
for (var i = 0; i < koChanges.length; i++) {
if (grid._edit._updatedRecords.indexOf(koChanges[i].data) == -1)
grid._edit._updatedRecords.push(koChanges[i].data);
}
}
else
grid._edit._updatedRecords = ko.utils.arrayMap(koChanges, function (obj) { return obj.data; });
}
syncJsMap is the Knockout.js extension I created for converting the JSON data source to Knockout’s model-based data source. Here is the code I used:
ko.syncJsMap = function (obj, viewModel) {
if (obj.length) {
var mapArray = [];
for (var i = 0; i < obj.length; i++) {
mapArray.push(new viewModel(obj[i]));
}
return mapArray;
}
}
Playing with the JSON Collection
Now it’s time to play with the results of the previous processes. I have written some HTML and JavaScript to produce the following functionality:
Upon clicking Change, the concerned JSON data will be updated using Knockout’s ViewModel. The code for that is as follows:
$("#butChange").click(function () {
var rowIndex = parseInt($("#rowIndex").val(), 10);
var columnName = $("#selectColumn").val()
var value = $("#change").val();
// The JSON collection can be changed like this. This will update the grid's UI as well as the data source.
page.dataSource()[rowIndex][columnName](value);
});
Once Change is clicked, you’ll see the updates in the grid as well. Please refer to the following screenshot:
You can see in the previous screenshot that the updated row will have a red mark. Click on the save icon in the grid’s toolbar to store data in the database and clear all dirty items.
You can find a downloadable version of this sample here: https://www.syncfusion.com/downloads/Support/DirectTrac/General/JsonCollection%20Change576454545.zip