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