Refactoring and inheritance

In this part we will discover how to setup base controllers for the standard operations and how to build an application in minutes.

The samples can be run with Firefox, in general or by running, into the directory,

Download

The source for this part is here: 07_inherit.zip.

The image is roialty free... taken from freedigitalphotos.net, nothing on the UI changes with this step!

Kitten with Santa hat

Kitten...a-hem Angular Controllers inheritance

Given a controller with a service

myApp.service('myService',[function....]);

myApp.controller('BaseController',['$scope','$http','myService',function($scope,$http,myService){
    ...
}]);

I can create a controller that inherits all its behaviours, variables etc. But i must add the dependency from the $controller service.

Note that we pass an object to the base controller, the scope, that must be passed to keep the same context as the child controller. We don't pass the $http and myService services, since they will be resolved automatically by Angular dependency injection

myApp.controller('InheritedController',['$scope',function($scope){
    $controller('BaseController',{$scope:$scope});
    ...
}]);

Refactoring...mostly everything

Our aim is to build generic CRUD controllers to avoid rewriting all the boring logic for ever and ever again.

The sgDialogService

First we will use this awesome library for the dialogs derived from the tutorial. Can be founded here following the installation instruction. We replace all call to modalDialogService to sgDialogService.

The code

Adding the dataService "interface"

We define an "interface" that we will follow with all that is needed to manage our customers. Here we define

customers.service('customersDataService', [function() {
    this.newTemplate='app/customers/new.html';
    this.detailTemplate='app/customers/detail.html';
    this.editTemplate='app/customers/edit.html';
    
    this.deleteConfirm=function(item){ return "You want to delete customer n."+item.id+"?";}
    
    this.detailMessage = function(item){return "Customer "+item.id;}
    this.editMessage = function(item){return "Editing Customer "+item.id;}
    this.createMessage = function(){return "Create Customer";}
        
    this.list=function(){ return "/customers";};
    this.get = function(item){ return '/customers/'+item.id;}
    this.put = function(item){return '/customers/'+item.id;}
    this.add = function(item){return '/customers';}
    this.delete=function(item){return '/customers/'+item.id;}
}])

Then we add to all the customers controller a dependency on this service and we replace all the instances of the given string and replace them. For example the addNew

        $scope.addNew = function(){
            globalModalService.openModal(
                {
                    template:'app/customers/new.html',
                    callback: function(){ $scope.loadData();}
                })
        }

Becomes the following, adding even the call to "loadData" to refresh the list automatically when adding items. Note the callback result

        $scope.addNew = function(){
            sgDialogService.openModal(
                {
                    templateUrl:dataService.newTemplate,
                    callback: function(){ $scope.loadData();}
                })
        }

Changing data binding

All the references to $scope.customer or $scope.customers will be changed to $scope.data.

At the same time when we iterate on the customers on the list, we will iterate on data, and when on the detail, edit and new we will use "data" as model.

Adding to the common module.

Now we will create a new "controller.js" under the commons directory and we will move all the controllers there. The controllers will be created as children of the "commonModule" and their names will be transformed like CustomersListController in ListController and so on.

The dependency from the customersDataService will become a dependency on a generic "dataService".

Implementing the REAL controllers

We will now add our new controllers into the customers module! For example the following. Note that

The same must be done for all the controllers.

customers.controller('CustomersListController',['$scope','$http','globalMessagesService',
        '$controller','customersDataService',
    function($scope,$http,globalMessagesService,$controller,customersDataService){
        $controller('ListController',{
            $scope:$scope,
            dataService:customersDataService
        });
}]);

The callbacks

Since we are creating a library we must add callbacks to the base controller. We define another "interface". That we add as a dependency to all our base controllers.

commonControllersCallbacks={
    postLoadData:function(data),
    postGet:function(data),
    preSave:function(data),
    postSave:function(data),
    postGetUpdate:function(data),
    preUpdate:function(data),
    postUpdate:function(data),
    preDelete:function(data),
    postDelete:function(data)
}

We define a default service that does nothing (to limit the code to write :P )

common.service('commonControllersCallbacks',[function(){
    return {}
}]);

For example the edit controller becomes the following with the commonControllersCallback. (Note the name inside the parameter is changed for brevity to "callbacks", the important is the "string" name of the parameter)

All the functions are verified for the existence!!


common.controller('EditController',['$scope','$http','$location','$routeParams','globalMessagesService','modalInstance',
        'dataService','commonControllersCallbacks',
    function($scope,$http,$location,$routeParams,globalMessagesService,modalInstance,dataService,callbacks){
        ...
        
        $http.get(dataService.get($scope.item)).
            success(function(data, status, headers, config) {
                ...
                //HERE IS ADDED THE CALLBACK
                if(callbacks.postGetUpdate)callbacks.postGetUpdate($scope.data);
        ...
            
        var update = function(){
        
            //HERE IS ADDED THE CALLBACK
            if(callbacks.preUpdate && !callbacks.preUpdate($scope.data))return;
            $http.put(dataService.put($scope.data),$scope.data).
                success(function(result, status, headers, config) {
                
                    //HERE IS ADDED THE CALLBACK
                    if(callbacks.postUpdate)callbacks.postUpdate($scope.data);
                    modalInstance.closeModal();
                }).

And to add the callbacks we will simply do the following (if needed!)

customers.controller('CustomerEditController',['$scope','$http','$location','globalMessagesService',
        '$controller','modalInstance','customersDataService',
    function($scope,$http,$location,globalMessagesService,$controller,modalInstance,customersDataService){
        $controller('EditController',{
            $scope:$scope,
            dataService:customersDataService,
            modalInstance:modalInstance,
            commonControllersCallbacks:{
                postUpdate:function(item){ alert("Item updated!!");}
            }
        })
}]);

Last modified on: April 16, 2015