Search code examples
javascriptasp.net-mvcangularjskendo-uiodata

How to get AngularJS and KendoUI working in harmony?


In stages, I setup my .Net MVC solution and ensured both Angular JS and KendoUI are working independently.

app.js:

var app = angular.module("app", ['kendo.directives']);

and in my controller, I have the following defined:

app.controller('contentTypesController', ['$scope', '$log', 'contentTypesRepository',
    function ($scope, $log, contentTypesRepository) {

        var a = {};

        $scope.status;
        $scope.contentTypes;

        $scope.contentTypeOptions;

        // for testing purposes, but not used - used for navigation properties
        $scope.users;

        getContentTypes();

        function getContentTypes() {
            // call the data repository
            contentTypesRepository.getList()
                .success(function (contentTypes) {
                    //console.log(contentTypes.value[0].Description);
                    //$log.log(contentTypes.value[0].Description)
                    $scope.contentTypes = contentTypes;
                    $scope.contentTypeOptions = {
                        dataSource: {
                            data: contentTypes
                        },
                        dataTextField: "Description",
                        dataValueField: "ContentTypeId",
                        optionLabel: "Select a Content Type"
                    };

                })
                .error(function (error) {
                    $scope.status = 'Unable to load data: ' + error.message;
                });
        }

        $scope.updateContentTypes = function (id) {
            var contentType;

            for (var i = 0; i < $scope.contentTypes.length; i++) {
                var currentType = $scope.contentTypes[i];
                if (currentType.ID === id) {
                    contentType = currentType;
                    break;
                }
            }
        };

        $scope.insertContentType = function () {
            // get contentType description from the client
            var contentType = { 'Description': $scope.newContentType };

            contentTypesRepository.insert(contentType)
                .success(function () {
                    $scope.status = 'Added new content type.  Refreshing list.';
                    // add the new content type to the client-side collection
                    $scope.contentTypes.value.push(
                                    { 'Description': $scope.newContentType }
                                );
                    $scope.newContentType = "";
                })
                .error(function (error) {
                    $scope.status = 'Unable to insert new content type: ' + error.message;
                });
        };

        $scope.deleteContentType = function(id) {
            contentTypesRepository.remove(id)
                .success(function () {
                    $scope.status = 'Deleted content type.  Refreshing list.';
                    for (var i = 0; i < $scope.contentTypes.length; i++) {
                        var contentType = $scope.contentTypes[i];
                        if (contentType.ID === id) {
                            // remove the content type from the client-side collection
                            $scope.contentTypes.splice(i, 1);
                            break;
                        }
                    }
                    // navigation properties = null
                    // $scope.xxxx = null;
                })
                .error(function (error) {
                    $scope.status = 'Unable to delete content type: ' + error.message;
                });
        };

        // get some navigation property
        //$scope.getCustomerOrders = function (id) {
        //    dataFactory.getOrders(id)
        //    .success(function (orders) {
        //        $scope.status = 'Retrieved orders!';
        //        $scope.orders = orders;
        //    })
        //    .error(function (error) {
        //        $scope.status = 'Error retrieving customers! ' + error.message;
        //    });
        //};


        $scope.addContentType = function () {

            //return $scope.newContentType.$save();
            $scope.contentTypes.value.push(
                { 'Description': $scope.newContentType }
            );
            $scope.newContentType = "";
        }

In following the Angluar/Kendo examples here, I added code related to $scope.contentTypeOptions.

In my view:

<select kendo-drop-down-list k-options="contentTypeOptions"></select>

Which displays a dropdown, but no data.

I am able to view the data in a ng-repeater:

                        <ul>
                            <li ng-repeat="contentType in contentTypes.value">
                                {{ contentType.Description }}
                            </li>
                        </ul>

And the raw data by {{ contentTypeOptions }}.

Since the repeater uses contentTypes.value, I tried this as well in

                    $scope.contentTypeOptions = {
                        dataSource: {
                            data: contentTypes.value  // tried both contentTypes and contentTypes.value
                        },
                        dataTextField: "Description",
                        dataValueField: "ContentTypeId",
                        optionLabel: "Select a Content Type"
                    };

... which is based on the JSON data:

enter image description here

Ultimately, I would like to get all the CRUD hooked up for a grid (which I have done in the past with OData, but now adding AngularJS to the mix) and thought simply displaying the data in an Angular/Kendo mix would be a good start. I'm hoping that after getting this pinned down the rest will be simple, and appreciate any suggestions.


Solution

  • Your code is a bit confusing since methods like $scope.updateContentTypes treat $scope.contentTypes as an array, but at the same time contentTypes appears to be an object with a property value which is an array.

    One thing to be aware of is that Kendo UI widgets will convert your array to a Kendo DataSource internally. This means that changes you make to $scope.contentTypes won't affect the items in your data source in $scope.contentTypeOptions.

    Another issue is that there is no full two-way binding between widgets and the data source in angular-kendo, and until recently, the data source wouldn't update at all unless you specifically declared it as a DataSource. There have been some improvements lately, although it's still not fully integrated, as far as I can see. (you can try creating a deep watch on the data yourself, but that may create performance problems; see related post here).

    Your dropdown doesn't show the data because you replace $scope.contentTypeOptions after creating the widget, and there is no $watch on that property that would update the widget with these options. You can either create a DataSource explicitly and update that with:

    $scope.contentTypeOptions.dataSource.data(contentType.value);
    

    or you can use the attribute:

    k-data-source="contentTypes" 
    

    which will create a $watch on $scope.contentTypes, so when you replace it, the widget will update as well.

    Maybe this basic (although admittedly a bit messy) example will help you somewhat (I set up the 2nd dropdown in the same way you did; the "change" button updates the data source).