Search code examples
mvvmkendo-uikendo-mobilekendo-mvvm

Data bound object in Kendo UI MVVM


Perhaps I'm misunderstanding the concept of Kendo's MVVM implementation, but... I have a simple Kendo UI Mobile view that is data-bound to a view model:

var myViewModel = kendo.observable({
    myEntity: null,

    onViewShow: function (e) {
        var bindingEntity = myStaticDataSource[0];
        myViewModel.set("myEntity", bindingEntity);
    }
});

myStaticDataSource is a static array of "entities" as simple JavaScript objects, with fields like name or description.

The view and its input fields are bound to the view model:

<div data-role="view" data-layout="default" data-model="myViewModel" data-bind="events: { show: onViewShow }">
    <form>
        <ul data-role="listview" data-style="inset">
            <li>
                <label>
                    Name
                    <input type="text" data-bind="value: myEntity.name" />
                </label>
            </li>
        </ul>
    </form>
</div>

When the user changes the input field, the corresponding field (e.g. name) is updated in the data-bound view model entity myEntity. But: what I would have expected is that the entity in myStaticDataSource is updated as well, since I'm not cloning objects. But it isn't! Its value remains on the original value. Why is this? Am I missing something about Kendo's MVVM handling?


Solution

  • This is a side-effect of Kendo Observable objects and arrays. When you assign a property to an ObservableObject using the .set() method, it wants to make that assigned item an observable as well. Your items in myStaticDataSource are probably plain JS objects and not Kendo Observables, so Kendo wraps the object into a new ObservableObject for you. This means that the objects are no longer the same.

    This might make more sense:

    var items = [{name: "item one"}];
    var vm = kendo.observable({item: undefined});
    vm.set("item", items[0]);
    vm.item === items[0]; // returns FALSE
    items[0] instanceof kendo.data.ObservableObject // returns FALSE
    vm.item instanceof kendo.data.ObservableObject // returns TRUE
    
    
    var items = kendo.observable([{name: "item one"}]);
    var vm = kendo.observable({item: undefined});
    vm.set("item", items[0]);
    vm.item === items[0]; // returns TRUE
    items[0] instanceof kendo.data.ObservableObject // returns TRUE
    vm.item instanceof kendo.data.ObservableObject // returns TRUE
    

    The "fix" for this is to do any one of:


    Make myStaticDataSource a Kendo DataSource, which will make all the items you put into it a ObservableObject.

    var myStaticDataSource = new kendo.data.DataSource({
        data: [
            {name: "Bob"}
        ]
    };
    

    Make myStaticDataSource a Kendo ObservableArray, which will make all the items you put into it a ObservableObject

    var myStaticDataSource = kendo.observable([
        {name: "Bob"}
    ]);
    

    Make each item in the myStaticDataSource array an ObservableObject

    var myStaticDataSource = [
        kendo.observable({name: "Bob"})
    ];