Marcel
Marcel

Reputation: 2158

The rows in a listView are not updating using Kendo MVVM

I am testing out Kendo's ui MVVM capabilities and can't seem to work out how to update the viewModel items so they update rows in a listView.

It updates fine if I replace all items with the new (json) items sent to me through a websocket but I am trying to simply update the matching items and expect to see these changes appear in my view (the listView div).

This is an extract of my code - what am I doing wrong?

<div id="listView">
    <table>
        <thead>
            <tr>
                <th>BatchID</th>
                <th>Status</th>
                <th>Progress</th>
                <th>Owner</th>
                <th>(Est)Completion Time</th>
            </tr>
        </thead>
        <tbody data-template="row-template" data-bind="source: items"></tbody>
        <tfoot data-template="footer-template" data-bind="source: this"></tfoot>
    </table>
</div>

then in my script blocks:

<script id="row-template" type="text/x-kendo-template">
    <tr>
        <td data-bind="text: BatchID"></td>
        <td data-bind="text: Status"></td>
        <td data-bind="text: Progress"></td>
        <td data-bind="text: Owner"></td>
        <td data-bind="text: EstCompletion"></td>
    </tr>
</script>

<script id="footer-template" type="text/x-kendo-template">
    <tr>
        <td>
            Batch count: #: total() #
        </td>
    </tr>
</script>

<script>

    $(document).ready(function () {

        var viewModel = kendo.observable({
            items: [],
            total: function () {
                return this.get("items").length;
            }
        });

        kendo.bind($("#listView"), viewModel);


        // register this reporting widget
        var webSocket = CreateSocket("screen2", "reporting", "default", true);

        webSocket.onmessage = function (e) {
            try {

                var smd = JSON.parse(e.data);
                var data = JSON.parse(smd.Data);

                jQuery.each(data, function () {

                    var id = this.BatchID;
                    var newItem = this;

                    var hasRow = false;
                    jQuery.each(viewModel.items, function () {
                        var itemTemp = this;
                        if (itemTemp.BatchID == id) {
                            hasRow = true;
                            itemTemp.Status == newItem.Status;
                            itemTemp.Progress = newItem.Progress;
                            itemTemp.EstCompletion = newItem.EstCompletion;
                            itemTemp.Completed = newItem.Completed;
                        }
                    });

                    if (!hasRow) {
                        var reportItem = new kendo.data.ObservableObject({
                            BatchID: "",
                            Owner: "",
                            Status: "",
                            Progress: "",
                            EstCompletion: "",
                            Completed: ""
                        });

                        reportItem.BatchID = this.BatchID;
                        reportItem.Owner = this.Owner;
                        reportItem.Status = this.Status;
                        reportItem.Progress = this.Progress;
                        reportItem.EstCompletion = this.EstCompletion;
                        reportItem.Completed = this.Completed;

                        viewModel.items.push(reportItem);
                    }

                });

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

        webSocket.onopen = function (e) {

            // now register our interest in receiving reporting monitoring data
            var bor = new SymMsgUp(GlobalInfo.UserID, "reporting", "default", "dfregister");

            // convert to Json and send it off the the server
            webSocket.send(bor.toServer());
        };

        webSocket.onclose = function (e) {
            //responseDiv.innerHTML += '<div>Disconnected.</div>';
        };

        webSocket.onerror = function (e) {
            //responseDiv.innerHTML += '<div>Error</div>'
        };



    });

</script>

The updates take place ( I checked with a debugger ) - but these changes are NOT reflected in the view..

Also, I created the var reportItem = new kendo.data.ObservableObject({ etc etc for testing - I rather not have to do this and simply dump the array of json objects into my observable collection (viewMode.Items). This works nicely but again it doesn't update when I update individual items...

Thanks in advance!

Upvotes: 4

Views: 3835

Answers (2)

Marcel
Marcel

Reputation: 2158

Just received an answer from Kendo (after almost a week because I am using a trial license...) on how this can be done:

$(function(){
  var viewModel = kendo.observable({
    products: [
        { name: "Hampton Sofa", price: 989.99, unitsInStock: 39 },
        { name: "Perry Sofa", price: 559.99, unitsInStock: 17 },
        { name: "Donovan Sofa", price: 719.99, unitsInStock: 29 },
        { name: "Markus Sofa", price: 839.99, unitsInStock: 3 }
    ],
    newPrice: 0,
    itemIndex: 0,
    setPrice: function(e){
      this.products[this.itemIndex].set("price", this.newPrice);
    }
});

kendo.bind($("body"), viewModel);

});

EDIT: Just to explain that the line that does the trick is:

this.products[this.itemIndex].set("price", this.newPrice);

This is what I was after - a way of updating an entry in their observable collection that DOES update the ui.

Upvotes: 3

OnaBai
OnaBai

Reputation: 40887

Not sure if it's a feature or a bug but what you are trying to do is not supported. If you update one element of your list then it is actually updated BUT if you update a field of one item of the list then it is not.

This means that only first level is actually observed.

So, what you should do is actually replace current element with the received one. Instead of:

if (itemTemp.BatchID == id) {
    hasRow = true;
    itemTemp.Status == newItem.Status;
    itemTemp.Progress = newItem.Progress;
    itemTemp.EstCompletion = newItem.EstCompletion;
    itemTemp.Completed = newItem.Completed;
}

you should:

jQuery.each(viewModel.items, function () {
    var itemTemp = this;
    if (itemTemp.BatchID == id) {
        hasRow = true;
        itemTemp.Status == newItem.Status;
        itemTemp.Progress = newItem.Progress;
        itemTemp.EstCompletion = newItem.EstCompletion;
        itemTemp.Completed = newItem.Completed;
    }
});

You should:

jQuery.each(viewModel.items, function (idx, old) {
    if (old.BatchID == id) {
        hasRow = true;
        viewModel.items.splice(idx, 1, newItem);
    }
});

BTW: did you realize that you had itemTemp.Status == newItem.Status; instead of itemTemp.Status = newItem.Status;

So, your code after some cleaning should read like:

webSocket.onmessage = function (e) {
    try {

        var smd = JSON.parse(e.data);
        var data = JSON.parse(smd.Data);

        jQuery.each(data, function () {
            var newItem = this;
            var hasRow = false;
            jQuery.each(viewModel.items, function (idx, oldItem) {
                if (oldItem.BatchID == newItem.BatchID) {
                    hasRow = true;
                    viewModel.items.splice(idx, 1, newItem);
                }
            });
            if (!hasRow) {
                viewModel.items.push(newItem);
            }
        });
    }
    catch (e) {
        //alert(e.message);
    }
};

Upvotes: 1

Related Questions