see sharper
see sharper

Reputation: 12035

Extending an object in javascript/angular

So I have a tree helper object in my angular app that provides a bunch of useful functions for dealing with the many tree structures in the app. This is provided by a factory, so each time some controller (or whatever) asks for a tree helper, it gets its own copy:

angular.module('MainApp').factory('TreeHelperFactory', 
function ($http, $q, $filter, DataService) {
    var treeHelper = new function ($http, $q, $filter, DataService) {
    ...
    code
    ...
})

Now I have a category service that provides various category-related functions, including returning a tree of categories and providing ways to manipulate that tree. So thinking like an OO developer, I reckon that the category service is really like a subclass of my tree helper, so I inject a tree helper instance and then attempt to extend that instance with category-specific functions, naively like this:

angular.module('MainApp').provider('CategoryService',
function() {
    this.$get = function ($http, $q, $filter, DataService, TreeHelperFactory) {
        var catService = TreeHelperFactory; 
        catService.listCategories = function() {...}
        catService.deleteCategory = function(id) {...}
        ... more code...
        return catService;
        }  
    }
);

But this doesn't work. The new properties are not visible when I try to invoke them later, only the tree helper properties of the original factory object. What am I missing and how do I achieve this?

Upvotes: 1

Views: 101

Answers (2)

Ilan Frumer
Ilan Frumer

Reputation: 32377

Services in angular.js are singletons, which means each time you inject a service it returns the exact same object, you cannot force it to return a new object each time it is injected.

What you can do is to create a Class function, for example:

angular.module('MainApp')

.factory('TreeHelperFactory', 
function ($http, $q, $filter, DataService) {

    /**
     * TreeHelper constructor
     * @class    
     */
    function TreeHelper() { /* this.init(); */ }

    /**
     * TreeHelper static class method
     */
    TreeHelper.list = function() { /* ... */ };

    /**
     * TreeHelper instance method
     */
    TreeHelper.prototype.init = function() { /*...*/ };

    /**
     * Returns the class
     */
    return TreeHelper;
})

Now you can inject it, instantiate an object and extend it like so:

.factory('CategoryService', function (TreeHelperFactory) {

  var catService = new TreeHelperFactory();

  catService.listCategories = function() { /*...*/ };
  catService.deleteCategory = function(id) { /*...*/ };

  return catService;
});

You can also use javascript prototypical inheritance but I think it's an overkill for most cases so keep it simple if you can.

Upvotes: 1

psp
psp

Reputation: 3374

Helper that depends on Angular services is a bad smell for me - almost like its status is more than a helper and it has a service or two in it. Would you be able to rethink this through restructuring their roles and responsibilities?

Upvotes: 0

Related Questions