1

If I need to reuse the following controller(placed in App.js), I need to remove the view specific columnDefs and place them separately(View, html file).

Here I have ui-grid's gridOptions set in the controller itself. Even if I manage to place that in UI(script tag), uiGridConstants is not available in the view. So how do I go about with this so I may reuse the file for multiple views. I am pulling my hair for quite some time now, and am a newbie on angular, so please help.

(function () {
    gridFactory = function ($http) {
        return {
            callWebApi: function () {
                return $http({
                    method: 'GET',
                    url: '/api/PatientCategoryApi/PatCat',
                    params: this.callParams.paginationOptions,
                    headers: { 'Content-Type': 'application/Json' }
                })
            },
            callParams: {}
        }
    };
    patientCategoryController = function ($scope, $attrs, uiGridConstants, gridFactory) {

        $scope.gridOptions = {

            paginationPageSizes: [5, 10, 20, 25, 50],
            paginationPageSize: 10,
            useExternalPagination: true,
            useExternalSorting: true,
            enableSorting: true,
            rowHeight: 30,
            columnDefs: [
                { field: 'Id', sortDirectionCycle:[uiGridConstants.ASC, uiGridConstants.DESC] },
                { field: 'Code' },
                { field: 'Name' },
                { field: 'Description' },
                { field: 'ModifiedTime', cellFilter: 'date:"dd-MMM-yy h:mm:ss a"' },
                { field: 'History', enableSorting: false }
            ],
            onRegisterApi: function (gridApi) {
                $scope.gridApi = gridApi;
            }
        };

        var callData = {};

        var paginationOptions = {};
        paginationOptions.Page = 1;
        paginationOptions.Take = 10;
        paginationOptions.SortOrder = 'Asc';
        paginationOptions.PropName = 'Id';
        callData.paginationOptions = paginationOptions;
        gridFactory.callParams = callData;
        var promise = gridFactory.callWebApi();
        promise.then(
            function successCallback(response) {
                $scope.gridOptions.totalItems = response.data.TotalCount;
                $scope.gridOptions.data = response.data.Collection;
                $scope.gridHeight = gridFactory.getGridHeight($scope.gridOptions);
            }, function errorCallback(response) {
                alert('Some problem while fetching data!!');
            });
    }
    patientCategoryController.$inject = ['$scope', '$attrs', 'uiGridConstants', 'gridFactory'];
    gridFactory.$inject = ['$http'];
    angular.module('abvhHisApp', ['ui.grid', 'ui.grid.autoResize', 'ui.grid.pagination', 'ui.grid.resizeColumns']);
    angular.module('abvhHisApp').controller('patientCategoryController', patientCategoryController);
    angular.module('abvhHisApp').factory('gridFactory', gridFactory);
}());

2 Answers 2

1

I had exactly the same problem having a number of grid views and wanted to write DRY code. My solution was to create a base class for the grid controllers and inherit it for different views.

Base class (providing infinite scrolling for the grid):

function InfiniteGrid() {
        var vm = this;

        vm.firstPage = vm.lastPage = 1;
        vm.keepPages = 3;
        vm.pageSize = 100;
        vm.totalCount = 0;

        vm.init();

        vm.data = vm.loadData();

        vm.uiGridOptions = {
            enableSorting: true
            ,columnDefs: vm.columnDefs
            ,data: 'vm.data'
            ,infiniteScrollRowsFromEnd: 1
            ,infiniteScrollUp: true
            ,infiniteScrollDown: true
            ,onRegisterApi: function(gridApi){
                gridApi.infiniteScroll.on.needLoadMoreData(vm.$scope, vm.getDataDown);
                gridApi.infiniteScroll.on.needLoadMoreDataTop(vm.$scope, vm.getDataUp);
                vm.gridApi = gridApi;
            }
        };

        vm.$scope.$watch('vm.filterText', function(search){
            vm.firstPage = vm.lastPage = 1;
            vm.data = vm.loadData(1, search);
        });

    }

    InfiniteGrid.prototype = {
        loadData : function (page, search) {
            var vm = this;
            return vm.Entity.query({page: page, limit: vm.pageSize, search: search}, function (data, headers) {
                vm.totalCount = data.total_count = 1 * headers('X-List-Total');
                vm.$timeout(function () {
                    vm.gridApi.infiniteScroll.dataLoaded(vm.firstPage > 1, vm.lastPage < Math.floor(vm.totalCount / vm.pageSize) + 1);
                });
            });
        },
        getDataDown : function () {
            var gridApi = this,
                vm = gridApi.grid.appScope.vm;
            vm.loadData(vm.lastPage + 1).$promise.then(function (newData) {
                vm.lastPage++;
                gridApi.infiniteScroll.saveScrollPercentage();
                vm.data = vm.data.concat(newData);
                gridApi.infiniteScroll.dataLoaded(vm.firstPage > 1, vm.lastPage < Math.floor(newData.total_count / vm.pageSize) + 1)
                    .then(vm.checkDataLength.bind(vm, 'up'));
            });
        },

        getDataUp : function () {
            var gridApi = this,
                vm = gridApi.grid.appScope.vm;
            vm.loadData(vm.firstPage - 1).$promise.then(function (newData) {
                vm.totalCount = newData.total_count;
                vm.firstPage--;
                gridApi.infiniteScroll.saveScrollPercentage();
                vm.data = newData.concat(vm.data);
                gridApi.infiniteScroll.dataLoaded(vm.firstPage > 1, vm.lastPage < Math.floor(newData.total_count / vm.pageSize) + 1)
                    .then(vm.checkDataLength.bind(vm, 'down'));
            });
        },

        checkDataLength : function (direction) {
            var vm = this;
            if (vm.lastPage - vm.firstPage > vm.keepPages) {
                if (direction === 'up') {
                    vm.data = vm.data.slice(vm.pageSize);
                    vm.firstPage++;
                    vm.$timeout(function () {
                        vm.gridApi.infiniteScroll.dataRemovedTop(vm.firstPage > 1, vm.lastPage < Math.floor(vm.totalCount / vm.pageSize) + 1);
                    });
                } else {
                    vm.data = vm.data.slice(0, vm.pageSize * vm.keepPages);
                    vm.lastPage--;
                    vm.$timeout(function () {
                        vm.gridApi.infiniteScroll.dataRemovedBottom(vm.firstPage > 1, vm.lastPage < Math.floor(vm.totalCount / vm.pageSize) + 1);
                    });
                }
            }
        },

        deleteRow : function (rowId) {
            var vm = this,
                row = vm.$filter('filter')(vm.data, {_id: rowId})[0],
                rowIdx = vm.data.indexOf(row);

            vm.Entity.delete({id: rowId}).$promise.then(function () {
                vm.data.splice(rowIdx, 1);
                vm.toastr.success("Record successfully deleted!", "Success", {extendedTimeOut: 1500, timeOut: 1500});
            }, function (data, status) {
                if (status !== 401) {
                    vm.toastr.error(data.data.message);
                }
            });
        }
    };

    return InfiniteGrid;
});

Inherited controller code

angular.module('myApp')
        .controller('SomeGridCtrl', ['$scope', '$timeout', '$resource', 'toastr', '$filter', '$routeParams', SomeGridCtrl]);

    function SomeGridCtrl($scope, $timeout, $resource, toastr, $filter, $routeParams)
    {
        var vm = this;
        $scope.vm = vm;
        vm.$scope = $scope;
        vm.toastr = toastr;
        vm.$filter = $filter;
        vm.$timeout = $timeout;
        vm.$resource = $resource;
        vm.$routeParams = $routeParams;

        // Call the parent constructor
        infiniteGrid.call(vm);
    }

    // Inherit the prototype
    SomeGridCtrl.prototype = Object.create(infiniteGrid.prototype);

    SomeGridCtrl.prototype.init = function() {
        var vm = this;

        vm.Entity = vm.$resource('/api/item/:id');
        vm.columnDefs = [
            {
                displayName: "Title"
                ,field: "title"
                //,filter: 'text',
                ,cellTemplate: '<div class="ui-grid-cell-contents"><a ng-href="#/card/{{ row.entity._id }}" ng-bind="COL_FIELD"></a></div>'
            },{
                displayName: "URL"
                ,field: "url"
                ,filter: 'text'
                ,cellTemplate: '<div class="ui-grid-cell-contents"><a ng-href="#/card/{{ row.entity._id }}" ng-bind="COL_FIELD"></a></div>'
            },{
                displayName: "Partner"
                ,field: "partner.fullName"
                //,filter: 'text'
            },{
                field: 'review_count'
                ,displayName: 'Reviews'
                ,width: 80
                ,cellTemplate: '<div class="ui-grid-cell-contents"><a ng-href="#/card/{{ row.entity._id }}/reviews" ng-bind="COL_FIELD"></a></div>'
            },{
                displayName: "Created on"
                ,field: 'created'
                ,cellFilter: 'amCalendar'
                ,filter: false
            },{
                displayName: "Delete"
                ,field: "dummy"
                //,width: 80
                ,cellTemplate: '<div class="ui-grid-cell-contents"><a ng-click="grid.appScope.vm.deleteRow(row.entity._id)" confirm="Are you sure?" class="btn btn-xs btn-danger">Delete</a></div>'
            }
        ];
    };

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks Constantine for the suggestion. I need to figure out how I could use it to my situation. Let you know once done. It will take some time.
0

OK, this is how I solved this.

What I wanted to achieve? I am using ui-grid of AngularJs in one of the pages. But I realized I have many such pages with grids to show lots of different tabulated data. So how to ensure DRY code is the question. @Constantine suggested inheritance using prototype pattern. So now to adapt that I started to search more for AngularJs controller inheritance and came across http://jasonwatmore.com/post/2014/03/25/AngularJS-A-better-way-to-implement-a-base-controller.aspx I tried this approach. Here is how.

App.js is as follows.

(function () {
    gridFactory = function ($http) {
        var service = {
            callWebApi: callWebApiFunction,
            callParams: {}
        };

        return service;

        function callWebApiFunction() {
            return $http({
                method: 'GET',
                url: this.callParams.uri,
                params: this.callParams.paginationOptions,
                headers: { 'Content-Type': 'application/Json' }
            })
        };
    }

    function baseGridController($scope, gridFactory) {
        $scope.diaryEntry = { name: 'default diary entry from baseGridController' };
        $scope.saveDiaryEntry = function () {
            gridFactory.SaveDiaryEntry($scope.diaryEntry);
        };

        // The following grid options are common fro all grids.
        // So the following code is shared.
        $scope.gridOptions.rowHeight = 30;
        $scope.gridOptions.useExternalPagination = true;
        $scope.gridOptions.useExternalSorting = true;
        $scope.gridOptions.enableSorting = true;
        $scope.gridOptions.onRegisterApi = function (gridApi) {
            $scope.gridApi = gridApi;
        }


        gridFactory.callParams = $scope.callData;
        var promise = gridFactory.callWebApi();
        promise.then(
            function successCallback(response) {
                $scope.gridOptions.totalItems = response.data.TotalCount;
                $scope.gridOptions.data = response.data.Collection;
            }, function errorCallback(response) {
                alert('Some problem while fetching data!!');
            });

    }

    angular.module('abvhHisApp', ['ui.grid', 'ui.grid.autoResize', 'ui.grid.pagination', 'ui.grid.resizeColumns']);
    angular.module('abvhHisApp').controller('baseGridController', baseGridController);
    baseGridController.$inject = ['$scope', 'gridFactory'];
    angular.module('abvhHisApp').factory('gridFactory', gridFactory);
    gridFactory.$inject = ['$http'];
}());

And in the html file, inside head tag, I have a script tag as follows.

<script type="text/javascript">
    (function () {
        'use strict';
        function patientCategoryController($scope, $controller, uiGridConstants) {
            $scope.gridOptions = {

                paginationPageSizes: [5, 10, 20, 25, 50],
                paginationPageSize: 10,
                // You can override the height and other properties here.
                //rowHeight: 60,
                columnDefs: [
                    { field: 'Id', sortDirectionCycle: [uiGridConstants.ASC, uiGridConstants.DESC] },
                    { field: 'Code' },
                    { field: 'Name' },
                    { field: 'Description' },
                    { field: 'ModifiedTime', cellFilter: 'date:"dd-MMM-yy h:mm:ss a"' },
                    { field: 'History', enableSorting: false }
                ]
            };

            var defaultCallData = {};
            var paginationOptions = {};
            paginationOptions.Page = 1;
            paginationOptions.Take = 10;
            paginationOptions.SortOrder = 'Asc';
            paginationOptions.PropName = 'Id';
            defaultCallData.paginationOptions = paginationOptions;
            defaultCallData.uri = '/api/PatientCategoryApi/PatCat';
            $scope.callData = defaultCallData;

            $controller('baseGridController', { $scope: $scope });
        }

        angular.module('abvhHisApp').controller('patientCategoryController', patientCategoryController);
        patientCategoryController.$inject = ['$scope', '$controller', 'uiGridConstants'];
    }());
</script>

Note the following.

  1. Before the above script tag, inside the head tag, the following scripts should be referenced.

  2. App.js contents are listed above. ui-grid.js is the ui-grid code http://ui-grid.info/.

So by this you can have specific settings in the html pages script tag. And then the common code which can be shared will be in App.js file.

So far I feel this is an elegant approach.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.