Reputation: 25553
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);
}());
Upvotes: 1
Views: 2189
Reputation: 25553
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.
Before the above script tag, inside the head tag, the following scripts should be referenced.
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.
Upvotes: 0
Reputation: 1034
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>'
}
];
};
Upvotes: 1