2

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);
                }
            });
        }
}
Marcel
  • 2,148
  • 6
  • 31
  • 48
  • Why are people voting this down? – Marcel Feb 05 '13 at 14:53
  • You should use the transport: read of DataSource to get your data. – Daniel Lorenz Apr 22 '13 at 19:37
  • I don't feel like the Kendo DataSource for transport is exactly ideal. You have to define the scheme every single time you expect something from the server. The Knockout-Mapping plug-in is much more efficient for "developers" when we just want to get something on the screen. The Kendo Datasource takes too much time to configure it so everything works as expected. This is just my own opinion on the matter. – Mr. Young May 02 '13 at 15:55

3 Answers3

1

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);
    }
});
OnaBai
  • 40,767
  • 6
  • 96
  • 125
  • Hi Ona - my next Kendo entry I am going to address with 'Ona, can you help me?' :) - Unfortunately your suggestion does not work this time - I have again simultaneously created a ticket to Kendo as well so as soon as they answer I will post it. Thanks. – Marcel Feb 05 '13 at 10:16
  • Don't worry, I will keep an eye on your questions ;-) Did you check if the problem is when pushing the elements on the viewmodel or maybe rendering it? Do you have some JSFiddle that I might "play" with? – OnaBai Feb 05 '13 at 12:44
1

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.

Mr. Young
  • 2,364
  • 3
  • 25
  • 41
0

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);
CodingWithSpike
  • 42,906
  • 18
  • 101
  • 138