angular service inheritance

62 views
Skip to first unread message

Pavel Bosin

unread,
Apr 8, 2014, 3:07:51 AM4/8/14
to ang...@googlegroups.com
My project deals with several types of business objects. Pages with lists (grids) are common. 
For example we may have a list of users, a list of client companies, and a list of promotions, etc. 
Each type of objects has own properties (column headers in the list, list filters, etc.). 
Each type of objects has its own end point in RESTful API. 

I had a separate repetitive angular service for each type. I.e. for type A:

angular.module('myApp').factory('AsService', function(Restangular) {
    var columnsArr = [ {field:"Name", title:gettext("A.."), ...},{...}...{...}];
    var listFilters = [{"id": 0, "code": "all", "name":"All" },...{...}];
    var apiUrl = '/as';

    return {
         columns: function() { return columnsArr; },
         filters: function() { return listFilters; },
         ...
         getObjet: function(id) {
             //use restangular with apiUrl to return object promise
         },
         getList: function() {
             //use restangular with apiUrl to return list promise
         }
    };
});

Very similar are "BsService" and "CsService". Each of them also has additional methods specific to their object type.

My goal was to set common functionality in DataObjService and extend AsService, BsService, and CsService from that common parent. 

I found few blog posts and forum discussions on the topic of services inheritance. 

My first approach was to add "init" method to the parent DataObjService. Then individual services look like this:

angular.module('myApp').factory('BsService', function(DataObjServ, Restangular) {
    var columnsArr = [ {field:"Name", title:gettext("A"), ...},{...}...{...}];
    var listFilters = [{"id": 0, "code": "all", "name":"All" },...{...}];
    var apiUrl = 'as';

    var theService = Object.create(DataObjServ);
    theService.init(columnsArr, listFilters, apiUrl, 'Bs');
    //additional methods like theService.bData = function() {...};
    return theService;
});


This works fine until more than one of these object types and services is needed in a page. Then it becomes clear that all services share the same closure in DataObjServ and each init call overwrites data set by the previous service. 
How can we fix this?

I then tried an approach, where DataObjServ looks more like this:

angular.module('myApp').factory('DataObjects', function(Restangular) {
    var DataObjects = function(columns, filters, url, objName) {
        this.columnsArr = columns; 
        //...
    };
    DataObjects.prototype.columns = function() {
        return this.columnsArr;
    };
    //...
    return DataObjects;
});

and other services like this:

angular.module('myApp').factory('Bs', function(DataObjects) {
    var bColumns = [ ... ],
        bListFilters = [ ... ],
        apiUrl = 'bs';
    //== make service from the parent
    var theService = function() {
        DataObjects.call(this, bColumns, bListFilters, apiUrl, 'Bs');
    };
    theService.prototype = new DataObjects(columnsArr, listFilters, apiUrl, 'Bs');
    //== additional child methods
    theService.prototype.items = function() { ... };

    return theService;
});

The result is that each instantiation of the service creates the new parent object, which solves the overwrite problem. 
But this comes at the cost that the controllers now have to create an object of BsService with "new" before using the service.

I wonder if there is a better way. For example maybe it is better to clone a parent service object before using it in the first approach with Object.create?

Any help is appreciated. 
 

Pavel Bosin

unread,
Apr 14, 2014, 2:17:18 PM4/14/14
to ang...@googlegroups.com
Found an easy solution. 
Make a parent service a simple function not via angular factory. 
And use factory pattern by calling this function in the child service: 
Reply all
Reply to author
Forward
0 new messages