33

I am fairly new to angularjs and am not able to find any documentation or examples for this. What I am looking to do is to extend a basic service so that i can use the methods defined under the basic service from other services. So for example say i have a basic service as follows.

angular.module('myServices', []).

    factory('BasicService', function($http){
        var some_arg = 'abcd'
        var BasicService = {
            method_one: function(arg=some_arg){ /*code for method one*/},
            method_two: function(arg=some_arg){ /*code for method two*/},
            method_three: function(arg=some_arg){ /*code for method three*/},
        });
        return BasicService;
    }   
);

Now i want to define an Extended service that extends from the above BasicService so that i can use methods defined under the BasicService from my extended service. Maybe something like:

    factory('ExtendedService', function($http){
        var ExtendedService = BasicService();
        ExtendedService['method_four'] = function(){/* code for method four */}
        return ExtendedService;
    }
Teo.sk
  • 2,619
  • 5
  • 25
  • 30
Amyth
  • 32,527
  • 26
  • 93
  • 135

6 Answers6

69

More cleaner and imperative way

.factory('ExtendedService', function($http, BasicService){

    var extended = angular.extend(BasicService, {})
    extended.method = function() {
        // ...
    }
    return extended;
}
S.C.
  • 2,844
  • 3
  • 26
  • 27
  • 10
    I think it's better to extend empty object instead of original service: `var extended = angular.extend({}, BasicService)`. Also `copy` will create new instance instead of extend with it's shallow copy – uladzimir Nov 24 '14 at 08:04
23

Your ExtendedServiceshould inject the BasicServicein order to be able to access it. Beside that BasicService is an object literal, so you can't actually call it as function (BasicService()).

.factory('ExtendedService', function($http, BasicService){
  BasicService['method_four'] = function(){};
  return BasicService;
}
Stewie
  • 60,366
  • 20
  • 146
  • 113
  • Am I right in saying this is the best method if we consider BasicService to be abstract? Because then we will never actually use BasicService, only ExtendedService so it is fine to literary extend it. – Floris Jul 14 '15 at 14:04
  • 1
    Is this method really ok? Given that services are singletons, this means that the change on BasicService will be permanent so BasicService will be changed as well. Wouldn't it be better to create a copy of BasicService and return the extended version of that copy? – Razvan Feb 05 '16 at 11:21
18

In my opinion, a better way:

.factory('ExtendedService', function($http, BasicService){
    var service = angular.copy(BasicService);

    service.methodFour = function(){
        //code for method four
    };

    return service;
});

Here at least does not change the inherited service.

Vitaly Sivkov
  • 407
  • 8
  • 14
3

Sorry if I post here but may be it's a good place to do it. I refer to this post

watch out to extend a service/factory because are singleton so you can extend a service/factory once.

'use strict';
            angular.module('animal', [])
                .factory('Animal',function(){
                        return {
                            vocalization:'',
                            vocalize : function () {
                                console.log('vocalize: ' + this.vocalization);
                            }
                        }

                });
                angular.module('dog', ['animal'])
                    .factory('Dog', function (Animal) {
                        Animal.vocalization = 'bark bark!';
                        Animal.color = 'red';
                        return Animal;
                    });

                angular.module('cat', ['animal'])
                   .factory('Cat', function (Animal) {
                        Animal.vocalization = 'meowwww';
                        Animal.color = 'white';
                        return Animal;
                    });
                 angular.module('app', ['dog','cat'])
                .controller('MainCtrl',function($scope,Cat,Dog){
                     $scope.cat = Cat;
                     $scope.dog = Dog;
                     console.log($scope.cat);
                     console.log($scope.dog);
                    //$scope.cat = Cat;
                });

but if you do like

'use strict';
            angular.module('animal', [])
                .factory('Animal',function(){
                    return function(vocalization){
                        return {
                            vocalization:vocalization,
                            vocalize : function () {
                                console.log('vocalize: ' + this.vocalization);
                            }
                        }
                    }
                });    
                angular.module('app', ['animal'])
                    .factory('Dog', function (Animal) {
                        function ngDog(){
                            this.prop = 'my prop 1';
                            this.myMethod = function(){
                                console.log('test 1');
                            }
                        }
                        return angular.extend(Animal('bark bark!'), new ngDog());
                    })
                    .factory('Cat', function (Animal) {
                        function ngCat(){
                            this.prop = 'my prop 2';
                            this.myMethod = function(){
                                console.log('test 2');
                            }
                        }
                        return angular.extend(Animal('meooow'), new ngCat());
                    })
                .controller('MainCtrl',function($scope,Cat,Dog){
                     $scope.cat = Cat;
                     $scope.dog = Dog;
                     console.log($scope.cat);
                     console.log($scope.dog);
                    //$scope.cat = Cat;
                });

it works

Community
  • 1
  • 1
Whisher
  • 31,320
  • 32
  • 120
  • 201
  • 1
    Good clarification but the angular.extend() takes care of that in a simpler way by making a copy of the service. – Bernard Aug 28 '14 at 11:30
1

I wrote an $extend provider that uses Backbone's extend under the hood -- So you get both prototype and static property extending in case you need them -- Plus you get parent/child constructors -- see gist @ https://gist.github.com/asafebgi/5fabc708356ea4271f51

a5af
  • 2,514
  • 2
  • 14
  • 13
-1

To expand on Stewie's answer, you could also do the following:

.factory('ExtendedService', function($http, BasicService){
    var service = {
        method_one: BasicService.method_one,
        method_two: BasicService.method_two,
        method_three: BasicService.method_three,
        method_four: method_four
    });

    return service ;

    function method_four(){

    }
}

This has the benefit that the original service is not altered, while keeping it's functionality. You can also choose to use your own implementations in the ExtendedService for the other 3 methods from BasicService.

  • Not the poster, but can someone explain why this solution was downvoted? It looks fine to me. – Floris Jul 14 '15 at 14:00
  • It seems, this post was downvoted because you need to list methods and fields that you got from parent object. This is bad practice for some reasons. Also technically this is not pure inheritance. – Akim Kelar Jul 22 '15 at 11:06