Dynamic data in the Kendo UI Grid

The moment you find yourself typing the same code over and over again, you know that something is off. You know that the code you are writing is getting WET (Write Everything Twice or We Enjoy Typing).

You need to stop, plan, modularize and DRY it off. You will thank yourself later when the next grid is up in seconds and you are sipping on that cup of of coffee you have been thinking of all afternoon.

Creating editable Kendo UI Grids with dynamic data is like cooking an a-la-carte meal the easy way. As a Technical Support Enginneer at Progress, I have seen plenty of our clients's "kitchens", helped resolve questions and given advice regarding dynamic data and I am here to give you the recipe.

Kendo UI Chef

The Dynamic Data Recipe

Ready in about 1 hour Medium level Serves: 1 editable and 1 non-editable grid

Ingredients

1. Consistent Backend Service and API
2. One initial ajax request
3. Client Grid Configuration
4. Client Data Source Configuration
Method

1. Create a backend with consistent naming of the controller actions. For example:

2. Write a function which creates a Kendo UI Grid with these parameters - gridName, baseUrl, editable and element. The function should make an ajax request and generate the schema model, columns and data source in the success callback. Once the schema, data source and columns are known, initialize the dynamic Kendo UI Grid and append it to the element.

The grid name - to create a <div id="[gridName]"></div> element with id equal to the name
The base URL - to make the initial AJAX request if the Kendo UI grid is editable, for the transport CRUD operations urls.
Editable - the boolean which will indicate whether the Kendo UI Grid is editable or not.
Optional - element to which the Kenod UI Grid element should be appended.
      // keep a reference of the date fields for easy formatting
      var dateFields = [];

      function createGrid(gridName, baseUrl, editable, element) {
        $.ajax({
          url: baseUrl,
          success: function(response) {
            var sampleDataItem = response[0];
            var model = generateModel(sampleDataItem);
            var dataSource = generateDataSource(baseUrl, model, editable);
            var columns = generateColumns(sampleDataItem);
            var gridOptions = {
              dataSource: dataSource,
              columns: columns,
              pageable: true,
              editable: editable,
              height: 450
            };
            
            if(editable){
              columns.push({ command: "destroy", title: " ", width: 170 });
              gridOptions.toolbar =  ["create", "save", "cancel"];
            }
            
            $("<div id='" + gridName + "'></div>").kendoGrid(gridOptions).appendTo(element);
          }
        });
      }
    

3. Create the helper functions for the data source schema model, columns and data source transport generation

A function to create the dynamic data source schema model

      function generateModel(sampleDataItem) {
        var model = {};
        var fields = {};
        for (var property in sampleDataItem) {
          if (property.indexOf("ID") !== -1 || property.indexOf("Id") !== -1) {
            model["id"] = property;
          }

          var propType = typeof sampleDataItem[property];
          if (propType === "number") {
            fields[property] = {
              type: "number"
            };
            if(model.id === property){
              fields[property].editable = false;
            }
          } else if (propType === "boolean") {
            fields[property] = {
              type: "boolean"
            };
          } else if (propType === "string") {
            var parsedDate = kendo.parseDate(sampleDataItem[property]);
            if (parsedDate) {
              fields[property] = {
                type: "date"
              };
              dateFields[property] = true;
            }
          }
        }

        model.fields = fields;

        return model;
      }
    

A function to create the dynamic columns

      function generateColumns(sampleDataItem) {
        var columnNames = Object.keys(sampleDataItem);
        return columnNames.map(function(name) {
          return {
            field: name,
            format: (dateFields[name] ? "{0:D}" : "")
          };
        });
      }
    

A function to create the dynamic data source

      function generateDataSource(baseURL, model, editable) {
        var dataSource = {
            transport: {
              read: {
                url: baseURL
              }
            },
            schema: {
              model:model
            },
            pageSize: 10
          };

        if (editable) {
          dataSource.transport.create = {
                url: baseURL + "Create"
              };
          dataSource.transport.update = {
                url: baseURL + "Update"
              };
          dataSource.transport.destroy = {
                url: baseURL + "Destroy"
              };
        }

        return dataSource;
      }
    

The result - initialization of two grids - one editable and one non-editable with these two lines of code:

        <div class="editable"></div>
        <div class="readonly"></div>
        <script>
         createGrid("products", "https://demos.telerik.com/kendo-ui/service/products/", true, ".editable");
         createGrid("customers", "https://demos.telerik.com/kendo-ui/service/customers/", false, ".readonly");
        </script>