Vue state does not sync with kendo datasource

878 Views Asked by At

I have a kendo wrapper grid with local kendo datasource pointing to vue state. There is a button "Update" which will update the state so that the grid will be updated as well and it works.

But if I firstly click the button "Test" (just only a same value assignment to state) and then click "Update", strangely it does not work so the grid has no change.

I finally found out the reason is that after clicked "Test" then "Update", the vue state updated but the kendo grid datasource won't (out of sync unexpectedly). Now the temp solution is I have to manually assign the state to the datasource so that the grid will be updated.

Repo: http://dojo.telerik.com/aGENIHuW

My question is why, after clicked 'Test', the kendo grid datasource became cached and out of sync with the vue state? If I don't click 'Test', they do sync always. Problem occur only when "same value assignment" to the state. If "different value assignment", no problem.

<div id="vueapp">
    <kendo-datasource ref="dsDS" :data="localDataSource"></kendo-datasource>
    <kendo-grid :data-source-ref="'dsDS'">
        <kendo-grid-column :field="'ProductID'"
                           :title="'ID'"
                           :width="40"></kendo-grid-column>
        <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>
    <input type="button" value="Test" @click="test" />
    <input type="button" value="Update" @click="update" />
</div>
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,
            }
        ]
    },
    methods: {
      test: function(e) {
        this.localDataSource = JSON.parse(JSON.stringify(this.localDataSource)); //same value assignment
        console.log('test');
      },
      update: function(e) {
        this.localDataSource.splice(0, 1, this.localDataSource[1]); //replace the first object with second object
      },
    }
})

Update:

Let me emphasize my question below:

Why test2() + update() => Works!

But test() + update() => NOT work

Their different is just the value assignment 'hello' for test2()

methods: {
    test: function(e) { //same value assignment
        let ds = JSON.parse(JSON.stringify(this.localDataSource));
        this.localDataSource = JSON.parse(JSON.stringify(ds));
    },
    test2: function(e) { //different value assignment
        let ds = JSON.parse(JSON.stringify(this.localDataSource));
        ds[0]['ProductName'] = 'hello';
        this.localDataSource = JSON.parse(JSON.stringify(ds));
    },
    update: function(e) {
        this.localDataSource.splice(0, 1, this.localDataSource[1]); //replace first row with second row
    }
}

http://dojo.telerik.com/aGENIHuW/10

2

There are 2 best solutions below

3
Joel H On

Once the datasource is set in the data() object, and the kendo grid is bound, I wouldn't try to edit the localDataSource object. The kendo grid gets your basic array and converts it into a kendo datasource with all the extended properties, so I would target that new object to make changes.

try something like below in your update method - if you can assign the grid an id through a wrapper attribute then the selector would be better than what i have here

    let gridDS = $("div[data-role=grid]").data("kendoGrid").dataSource;
    let data = gridDS.data();
    data.splice(0,1,data[1]);

btw the data method should return a new object otherwise you might have issues with duplicate components sharing the same object so instead of

    data:{
        localDataSource:[1,2,3]
    }

i would do

    data(){
        return {
            localDataSource:[1,2,3]
        }
    }
1
Joel H On

Adding this as answer because comments won't accommodate this much text:

If you do a data dump after the update() function: console.table(this.localDataSource) you will see that the localDataSource array is being updated correctly. But the kendo grid isn't aware of it. It still has its own array of data. If you do a corresponding dump of the kendo data source, you will see it has not been synced

   let gridDS = $("div[data-role=grid]").data("kendoGrid").dataSource;
   let data = gridDS.data();
   console.table(data);

What I think is happening is this - since localDataSource is a property of data(), Vue observes any changes to its nested properties. When it executes code ds[0]['ProductName'] = 'hello' Vue picks up the update, looks for dependencies on the object, and rebinds the kendo-grid component.