Data Binding

The Kendo UI Grid wrapper for Vue enables you to bind it to a list of possible values.

To populate the Grid with data, bind it to either:

Binding to Local Data Arrays

To provide the Kendo UI Data Grid wrapper for Vue with local data:

  1. Define the array in the data object of the Vue application.
  2. Refer it during the initialization of the Grid through the :data-source property.
<div id="vueapp" class="vue-app">
    <kendo-grid :data-source="localDataSource">
    </kendo-grid>
</div>
Vue.use(GridInstaller);

new Vue({
    el: '#vueapp',
    data: {
        localDataSource: [{
            "ProductID": 1,
            "ProductName": "Chai",
            "UnitPrice": 18,
            "UnitsInStock": 39,
            "Discontinued": false,
        },
        {
            "ProductID": 2,
            "ProductName": "Chang",
            "UnitPrice": 17,
            "UnitsInStock": 40,
            "Discontinued": false,
        },
        {
            "ProductID": 3,
            "ProductName": "Aniseed Syrup",
            "UnitPrice": 10,
            "UnitsInStock": 13,
            "Discontinued": false,
        },
        {
            "ProductID": 4,
            "ProductName": "Chef Anton",
            "UnitPrice": 22,
            "UnitsInStock": 53,
            "Discontinued": false,
        },
        {
            "ProductID": 5,
            "ProductName": "Chef Gumbo Mix",
            "UnitPrice": 21.35,
            "UnitsInStock": 0,
            "Discontinued": true,
        },
        {
            "ProductID": 6,
            "ProductName": "Boysenberry Spread",
            "UnitPrice": 25,
            "UnitsInStock": 120,
            "Discontinued": false,
        }]
    }
})

Binding to Remote Data Services

For remote data binding you need to specify a remote endpoint or web service returning data in JSON/JSONP, OData or XML format, and utilize the DataSource component as a mediator between the Grid and the underlying data. To make the connection to the remote endpoint and process the data properly, the data source needs information about the web service URL(s), the request type, the response data type, and the structure (schema) of the response, in case it is more complex than a plain array of objects.

To provide the Kendo UI Data Grid wrapper for Vue with data by remote data services:

  1. Create a new Kendo UI Data Source object.
  2. To configure the data operation actions, such as Read, Update, Create, or Destroy, refer the remote data services by using the Transport object of the Data Source&mdashh;for example, :transport-read-url, :transport-update-url,and so on.
  3. Refer the Data Source object during the initialization of the Grid through the :data-source property.
<div id="vueapp" class="vue-app">
    <kendo-datasource ref="datasource1"
                        :transport-read-url="'https://demos.telerik.com/kendo-ui/service/Products'"
                        :transport-read-data-type="'jsonp'"
                        :transport-update-url="'https://demos.telerik.com/kendo-ui/service/Products/Update'"
                        :transport-update-data-type="'jsonp'"
                        :transport-destroy-url="'https://demos.telerik.com/kendo-ui/service/Products/Destroy'"
                        :transport-destroy-data-type="'jsonp'"
                        :transport-create-url="'https://demos.telerik.com/kendo-ui/service/Products/Create'"
                        :transport-create-data-type="'jsonp'"
                        :transport-parameter-map="parameterMap"
                        :schema-model-id="'ProductID'"
                        :schema-model-fields="schemaModelFields"
                        :batch='true'
                        :page-size='20'>
    </kendo-datasource>

    <kendo-grid :height="600"
                :data-source-ref="'datasource1'"
                :pageable='true'
                :editable="'inline'"
                :toolbar="['create']">
        <kendo-grid-column :field="'ProductName'"></kendo-grid-column>
        <kendo-grid-column :field="'UnitPrice'"
                           :title="'Unit Price'"
                           :width="120"
                           :format="'{0:c}'"></kendo-grid-column>
        <kendo-grid-column :field="'UnitsInStock'"
                           :title="'Units In Stock'"
                           :width="120"></kendo-grid-column>
        <kendo-grid-column :field="'Discontinued'"
                           :width="120"></kendo-grid-column>
        <kendo-grid-column :command="['edit', 'destroy']"
                           :title="'&nbsp;'"
                           :width="170"></kendo-grid-column>
    </kendo-grid>
</div>
Vue.use(GridInstaller);
Vue.use(DataSourceInstaller);

new Vue({
    el: '#vueapp',
    data: {
        schemaModelFields: {
            ProductID: { editable: false, nullable: true },
            ProductName: { validation: { required: true } },
            UnitPrice: { type: 'number', validation: { required: true, min: 1 } },
            Discontinued: { type: 'boolean' },
            UnitsInStock: { type: 'number', validation: { min: 0, required: true } }
        }
    },
    methods: {
        parameterMap: function(options, operation) {
            if (operation !== 'read' && options.models) {
                return { models: kendo.stringify(options.models) };
            }
        }
    }
})

Binding to GraphQL Service

A GraphQL service is served over HTTP through a single endpoint and expresses the full set of capabilities of the API. Also, a GraphQL service usually responds with JSON, thus making it very easy to integrate with the Grid component through a more advanced data source configuration.

The following example demonstrates how to setup the Grid to perform CRUD operations through GraphQL queries and mutations. The service that is used is implemented in ASP.NET Core and is available for review in the following GitHub repository.

<div id="vueapp" class="vue-app">
    <kendo-datasource ref="datasource"
                      :schema-model-id="'productID'"
                      :schema-model-fields="schemaModelFields"
                      :schema-data="schemaData"
                      :schema-total="schemaTotal"
                      :transport-create-url="'https://demos.telerik.com/aspnet-core/service/api/graphql/'"
                      :transport-create-content-type="'application/json'"
                      :transport-create-type="'POST'"
                      :transport-create-data="additionalParamsOnCreate"
                      :transport-read-url="'https://demos.telerik.com/aspnet-core/service/api/graphql/'"
                      :transport-read-content-type="'application/json'"
                      :transport-read-type="'POST'"
                      :transport-read-data="additionalParamsOnRead"
                      :transport-update-url="'https://demos.telerik.com/aspnet-core/service/api/graphql/'"
                      :transport-update-content-type="'application/json'"
                      :transport-update-type="'POST'"
                      :transport-update-data="additionalParamsOnUpdate"
                      :transport-destroy-url="'https://demos.telerik.com/aspnet-core/service/api/graphql/'"
                      :transport-destroy-content-type="'application/json'"
                      :transport-destroy-type="'POST'"
                      :transport-destroy-data="additionalParamsOnDestroy"
                      :page-size="20"
                      :transport-parameter-map="parameterMap">
    </kendo-datasource>

    <kendo-grid ref="grid"
                :height="550"
                :data-source-ref="'datasource'"
                :groupable="true"
                :sortable="true"
                :pageable="true"
                :editable="'inline'"
                :toolbar="['create']">
        <kendo-grid-column :field="'productID'" :title="'Product ID'"></kendo-grid-column>
        <kendo-grid-column :field="'productName'" :title="'Product Name'"></kendo-grid-column>
        <kendo-grid-column :field="'unitPrice'"
                           :title="'Unit Price'"
                           :format="'{0:c}'"></kendo-grid-column>
        <kendo-grid-column :field="'unitsInStock'"
                           :title="'Units in Stock'"></kendo-grid-column>
        <kendo-grid-column :command="['edit', 'destroy']"
                           :title="'Options'"
                           :width="200"></kendo-grid-column>
    </kendo-grid>
</div>
Vue.use(GridInstaller);
Vue.use(DataSourceInstaller);

new Vue({
    el: '#vueapp',
    data: {
        schemaModelFields: {
            productID: { type: 'number', editable: false },
            productName: { validation: { required: true } },
            unitPrice: { type: 'number', validation: { required: true, min: 1 } },
            unitsInStock: { type: 'number', validation: { min: 0, required: true } }
        }
    },
    methods: {
        schemaData: function(response) {
            var data = response.data;

            if (data.products) { return data.products; }
            else if (data.createProduct) { return data.createProduct; }
            else if (data.updateProduct) { return data.updateProduct; }
            else if (data.deleteProduct) { return data.deleteProduct; }
        },
        schemaTotal: function(response) {
            return response.data.products.length;
        },
        parameterMap: function(options, operation) {
            return  kendo.stringify({
                query: options.query,
                variables: options.variables
            });
        },
        additionalParamsOnCreate: function(model) {
            var createQuery = "mutation CreateProductMutation($product: ProductInput!){" +
                "createProduct(product: $product){" +
                    "productID,"+
                    "productName,"+
                    "unitPrice,"+
                    "unitsInStock"+
                "}"+
            "}";

            return {
                query: createQuery,
                variables: { "product": model }
            };
        },
        additionalParamsOnRead: function(model) {
            var readQuery = "query {" +
                "products { productID, productName, unitPrice, unitsInStock }" +
            "}";

            return { query: readQuery };
        },
        additionalParamsOnUpdate: function(model) {
            var updateQuery = "mutation UpdateProductMutation($product: ProductInput!){" +
                "updateProduct(product: $product){" +
                    "productID,"+
                    "productName,"+
                    "unitPrice,"+
                    "unitsInStock"+
                "}" +
            "}";

            return {
                query: updateQuery,
                variables: { "product": model }
            };
        },
        additionalParamsOnDestroy: function(model) {
            var deleteQuery = "mutation DeleteProductMutation($product: ProductInput!){" +
                "deleteProduct(product: $product){" +
                    "productID,"+
                    "productName,"+
                    "unitPrice,"+
                    "unitsInStock"+
                "}"+
            "}";

            return {
                query: deleteQuery,
                variables: { "product": model }
            };
        }
    }
})

Binding to WebSocket

The Grid allows you to perform real-time updates for all users who start a session with your web application. In such cases, you can utilize WebSockets and the DataSource component. For handling data requests, the DataSource supports WebSockets through the transport->push/read/update/destroy/create configurations. The setting of those methods enable the long polling process—that is, the data source uses web sockets for transmitting and operating with the data in real time on every page refresh.

The following example demonstrates how to implement real-time push-notifications from a WebSocket. To see the real-time updates:
1. Open the page in two browser windows.
1. Create, update, or destroy Grid items.

<div id="vueapp" class="vue-app">
    <kendo-datasource ref="datasource1"
                      :auto-sync="true"
                      :sort="defaultSort"
                      :schema-model-id="'ProductID'"
                      :schema-model-fields="schemaModelFields"
                      :schema-data="'data'"
                      v-on:error="onError"
                      :transport-push="onPush"
                      :transport-read="onRead"
                      :transport-update="onUpdate"
                      :transport-destroy="onDestroy"
                      :transport-create="onCreate">
    </kendo-datasource>

    <kendo-grid ref="grid"
                :height="550"
                :data-source-ref="'datasource1'"
                :auto-bind="false"
                :editable="true"
                :sortable="true"
                :toolbar="['create']">
        <kendo-grid-column :field="'ProductName'" :title="'Product Name'"></kendo-grid-column>
        <kendo-grid-column :field="'UnitPrice'"
                           :title="'Unit Price'"
                           :width="120"
                           :format="'{0:c}'"></kendo-grid-column>
        <kendo-grid-column :command="['destroy']"
                           :title="'&nbsp;'"
                           :width="100"></kendo-grid-column>
    </kendo-grid>
</div>
Vue.use(GridInstaller);
Vue.use(DataSourceInstaller);

new Vue({
    el: '#vueapp',
    created: function() {
        var that = this;
        var host = "wss://kendoui-ws-demo.herokuapp.com";
        that.ws = new WebSocket(host);

        //Bind the grid when the socket connects
        that.ws.onopen = function() {
          that.$refs.grid.kendoWidget().dataSource.read();
        };

        //Close the socket when the browser window is closed.
        window.onbeforeunload = function() {
          that.ws.close();
        }
    },
    data: {
        ws: null,
        schemaModelFields: {
            ProductID: { editable: false, nullable: true },
            CreatedAt: { type: "date" },
            UnitPrice: { type: "number" }
        },
        defaultSort: [{
            field: "CreatedAt", dir: "desc"
        }]
    },
    methods: {
        onPush: function(options) {
            var that = this;

            //Listen to the "message" event fired when the server pushes data
            that.ws.addEventListener("message", function(e) {
                var result = JSON.parse(e.data);

                //Check what the push type is and invoke the corresponding callback.
                if (result.type == "push-update") {
                    options.pushUpdate(result);
                } else if (result.type == "push-destroy") {
                    options.pushDestroy(result);
                } else if (result.type == "push-create") {
                    options.pushCreate(result);
                }
            });
        },
        onRead: function(options) {
            var that = this;
            var request = { type: "read" };

            that.send(that.ws, request, function(result) {
                options.success(result);
            });
        },
        onUpdate: function(options) {
            var that = this;
            var request = { type: "update", data: [options.data] };

            that.send(that.ws, request, options.success);
        },
        onDestroy: function(options) {
            var that = this;
            var request = { type: "destroy", data: [options.data] };

            that.send(that.ws, request, options.success);
        },
        onCreate: function(options) {
            var that = this;
            var request = { type: "create", data: [options.data] };

            that.send(that.ws, request, options.success);
        },
        onError: function(err) {
            alert(JSON.stringify(err));
        },
        send: function(ws, request, callback) {
            var that = this;

            if (that.ws.readyState != 1) {
                alert("Socket was closed. Please reload the page.");
                return;
            }

            //Assign unique id to the request. Will use that to distinguish the response.
            request.id = kendo.guid();

            //Listen to the "message" event to get server response
            that.ws.addEventListener("message", function(e) {
                var result = JSON.parse(e.data);

                //Check if the response is for the current request
                if (result.id == request.id) {
                    //Stop listening
                    that.ws.removeEventListener("message", that.ws);

                    //Invoke the callback with the result
                    callback(result);
                }
            });

            //Send the data to the server
            that.ws.send(JSON.stringify(request));
        }
    }
})

Working Offline

The DataSource component provides built-in options for interacting with the web application, modifying its data, and storing the changes when no internet connection is available. The DataSource also enables the server syncing of the offline updates that will follow when the internet connection is restored. To enable and also customize the offline data storage, use the default offline-storage setting of the DataSource, and utilize its online and offlineData methods.

The following example demonstrates how to edit, create, or delete records, and persist these changes in the Grid when you are offline, and then sync the updates when you are back online. The DataSource acts as a mediator between the Grid and the underlying data.

<div id="vueapp" class="vue-app">
    <kendo-datasource ref="datasource1"
                      :offline-storage="'offline-kendo-demo'"
                      :transport-read-url="'https://demos.telerik.com/kendo-ui/service/Products'"
                      :transport-read-data-type="'jsonp'"
                      :transport-update-url="'https://demos.telerik.com/kendo-ui/service/Products/Update'"
                      :transport-update-data-type="'jsonp'"
                      :transport-destroy-url="'https://demos.telerik.com/kendo-ui/service/Products/Destroy'"
                      :transport-destroy-data-type="'jsonp'"
                      :transport-create-url="'https://demos.telerik.com/kendo-ui/service/Products/Create'"
                      :transport-create-data-type="'jsonp'"
                      :transport-parameter-map="parameterMap"
                      :schema-model-id="'ProductID'"
                      :schema-model-fields="schemaModelFields"
                      :batch='true'
                      :page-size='20'>
    </kendo-datasource>

    <kendo-grid ref="grid"
                :height="600"
                :data-source-ref="'datasource1'"
                :pageable-refresh='true'
                :editable="'inline'"
                :toolbar="['create']">
        <kendo-grid-column :field="'ProductName'"></kendo-grid-column>
        <kendo-grid-column :field="'UnitPrice'"
                           :title="'Unit Price'"
                           :width="120"
                           :format="'{0:c}'"></kendo-grid-column>
        <kendo-grid-column :field="'UnitsInStock'"
                           :title="'Units In Stock'"
                           :width="120"></kendo-grid-column>
        <kendo-grid-column :field="'Discontinued'"
                           :width="120"></kendo-grid-column>
        <kendo-grid-column :command="['edit', 'destroy']"
                           :title="'&nbsp;'"
                           :width="170"></kendo-grid-column>
    </kendo-grid>
</div>
Vue.use(GridInstaller);
Vue.use(DataSourceInstaller);

new Vue({
    el: '#vueapp',
    data: {
        schemaModelFields: {
            ProductID: { editable: false, nullable: true },
            ProductName: { validation: { required: true } },
            UnitPrice: { type: 'number', validation: { required: true, min: 1 } },
            Discontinued: { type: 'boolean' },
            UnitsInStock: { type: 'number', validation: { min: 0, required: true } }
        }
    },
    methods: {
        parameterMap: function(options, operation) {
            if (operation !== 'read' && options.models) {
                return { models: kendo.stringify(options.models) }
            }
        }
    },
    mounted: function() {
        this.$refs.grid.kendoWidget().dataSource.online(false);
    }
})

In this article