Changing Angular model to update Kendo

4.3k views Asked by At

I've been using Angular for a project and just recently found out about the Kendo-Angular project over at http://kendo-labs.github.io/angular-kendo/#/. I was successful in adding Angular-Kendo into my project and it's working like I think it should with the exception of updating models like I'm used to.

This project is exactly what I am looking for, however, no examples in the documentation actually show you being able to update an Angular model so it updates a Kendo data source.

Here is a piece of code for example:

$scope.data = new kendo.data.DataSource({
    data: [{
        name: "India",
        data: [10, 7.943, 7.848, 9.284, 9.263, 9.801, 3.890, 8.238, 9.552, 6.855]
    }, {
        name: "World",
        data: [1.988, 2.733, 3.994, 3.464, 4.001, 3.939, 1.333, 2.245, 4.339, 2.727]
    }, {
        name: "Russian Federation",
        data: [4.743, 7.295, 7.175, 6.376, 8.153, 8.535, 5.247, 7.832, 4.3, 4.3]
    }, {
        name: "Haiti",
        data: [0.253, 0.362, 3.519, 1.799, 2.252, 3.343, 0.843, 2.877, 5.416, 5.590]
    }]
});

With Angular, one would expect to make something like this:

<input ng-model="data[0].data[0]" />

The output in the input field would be 10. However, when passing this data to a graph and trying to change the value in the input box the graph doesn't update.

Anyone who has experience with these particular libraries know how to implement something like that? Does that support even exist? Is this just a library to make Kendo work with Angular and nothing more?

3

There are 3 answers

3
Sethen On

I solved this, but now in the way I was expecting.

I just tied a change event to the input and called the Kendo redraw() method and it redraws every time my model gets updated. A little annoying considering there is an entire effort for this over at Kendo. You would've thought that 2 way binding would be available.

Still looking for a better answer if one exists.

0
Lars Höppner On

Note that the author(s) of angular-kendo and/or people with more in-depth knowledge of AngularJS will probably stone me for "doing it wrong", but here goes:

angular-kendo already uses a $watch on the data source, so if you add some code to what it's doing there originally, for example like this:

scope.$watch(attrs.kDataSource, function (mew, old) {
    if (mew !== old) {
        element.data('$kendoDataSource', toDataSource(mew, type));

        var role = element.data("role");
        var widgetType = role.charAt(0).toUpperCase() + role.slice(1);
        var w = element.data("kendo" + widgetType);;

        if (!w) {
            w = kendo.widgetInstance(element, kendo.ui);
        }

        if (w && typeof w.setDataSource === "function") {
            w.setDataSource(element.data('$kendoDataSource'));
        }
    }
}, true);

then the behavior you were looking for works. I'm not sure why this (well, something like it, but much better) isn't implemented; to me, it seems like a core feature, but there are probably reasons which I don't understand (I haven't really read all of the source code here). In any case, having to manually attach a change event handler to an input to update your UI doesn't seem very "angular" to me either.

Demo for giggles. Disclaimer: I'm not responsible for anything. Don't use this.

Edit: after taking a look at the angular-kendo issue tracker, it looks like they intend to do something similar (judging from a comment by @BurkeHolland here), so maybe this is not completely wrong; I updated the demo to be a bit more readable

1
Dr. Mike Hopper On

I'm not crazy about this solution but I think this is the best way to do the binding at this time. The solution is to use either kendo.data.ObservableArray or kendo.data.DataSource to back the datagrid and then update the ObservableArray or DataSource in the controller:

angular.module('MyApp').controller('MyController', function($scope, $http) {
    $scope.products = new kendo.data.DataSource({
        data: [],            // kendo watches this array
        pageSize: 5
    });

    $http.get('data/products.json').then(function(result) {
        // update the Kendo DataSource here.
        $scope.products.data(result.data);
    });
});

The HTML looks like this:

<div kendo-grid
     k-data-source="products"
     k-selectable="'row'"
     k-columns='[{ "field": "ProductName",           "title": "Name" },
                 { "field": "Supplier.SupplierName", "title": "Supplier" },
                 { "field": "Category.CategoryName", "title": "Category" }]'
     k-sortable="true"
     k-groupable="true"
     k-filterable="true">
</div>