Marcel
Marcel

Reputation: 2158

MVVM binding to a Kendo Grid is VERY slow?

I am trying to bind a ViewModel to a Kendo DataSource which in turn is given to a Kendo Grid. Nothing too fancy at this point.

It sort of works but is VERY slow! I have an alert informing me that I have received my json data (700 rows) within 2 seconds but it then takes around 15 seconds to update the viewmodel.

What am I doing wrong?

Thanks

    $(document).ready(function () {

        // create the viewmodel we use as the source for the list
        var viewModel = kendo.observable({
            items: [],
            total: function () {
                return this.get("items").length;
            }
        });

        var dataSource2 = new kendo.data.DataSource({
            data: viewModel,
            pageSize: 50
        });

        // create the grid
        $("#grid").kendoGrid({
            dataSource: dataSource2,
            height: 500,
            scrollable: {
                virtual: true
            },
            columns: [
                { field: "ID_ORDER", title: "ID", width: 80 },
                { field: "CREATION_DATE", title: "Creation Date" },
                { field: "STATUS", title: "STATUS", width: 80 },
                ** more columns (around 10) **
            ]
        });

        // pass this on to initialise
        APPS.View.Orders.Initialise(viewModel);

    });

Then in my typescript I am handling the Initialise call where the viewModel is passed in:

    module APP.View.Orders {

        export var _Scope: string = "Orders";
        var _viewModelOrders: any;

        export var Initialise = function (viewModelOrders: any) {

            _viewModelOrders = viewModelOrders;

            var orderdetails = {
                userid: APP.Core.userID,
                context: "DEAL"
            };

            // retrieve all orders
            $.getJSON("/api/omsapi/GetOrders", orderdetails, function (mydata) {

                try {

                    alert("item count (1): " + mydata.length);

                    jQuery.each(mydata, function () {

                        var newItem = this;
                        _viewModelOrders.items.push(newItem);

                    });

                    alert("item count (2): " + _viewModelOrders.items.length);

                }
                catch (e) {
                    alert(e.message);
                }
            });
        }
}

Upvotes: 2

Views: 3260

Answers (3)

CodingWithSpike
CodingWithSpike

Reputation: 43728

To explain further, this is due to the line:

_viewModelOrders.items.push(newItem);

Each time you push an item into the array, it triggers a change event, which the Grid sees and updates itself. So if you push 700 items in, you are really causing the grid to update the DOM 700 times.

It would be much better to aggregate all the items into an array, then assign the array to the DataSource, with something like:

$.getJSON("/api/omsapi/GetOrders", orderdetails, function (mydata) {
    datasource2.data(mydata);

Upvotes: 0

Mr. Young
Mr. Young

Reputation: 2424

You can suspend the observable temporarily by doing the following:

$.getJSON("/api/omsapi/GetOrders", orderdetails, function (mydata) {
     try {
        var simpleArray = viewModel.items();  // get a reference to the underlying array instance of the observable
        jQuery.each(mydata, function () {
            items.push(this);
        });

        viewModel.items.valueHasMutated(); // let the observable know it's underlying data has been updated
     }
     catch (e) {
        alert(e.message);
    }
}

Doing the above technique dramatically improves loading times. I have testing this loading a few thousand rows in a reasonable time.

Upvotes: 1

OnaBai
OnaBai

Reputation: 40897

Try building the item array and then assign it into the model.

Something like:

// retrieve all orders
$.getJSON("/api/omsapi/GetOrders", orderdetails, function (mydata) {
    try {
        alert("item count (1): " + mydata.length);
        var items = [];
        jQuery.each(mydata, function () {
            items.push(this);
        });
        _viewModelOrders.items = items;
        alert("item count (2): " + _viewModelOrders.items.length);
    }
    catch (e) {
        alert(e.message);
    }
});

Upvotes: 1

Related Questions