9

I am working with AngularJS 1.x and I can define the same service multiple times in the same module. In the following snippet of code, I am defining the service nameService 2 times in module myApp:

(function() {
  'use strict';

  angular
    .module('myApp', [])
    .controller('MainController', MainController)
    .factory('nameService', nameService1)
    .factory('nameService', nameService2);

  MainController.$inject = ['nameService'];

  function MainController(nameService) {
    var vm = this;

    vm.message = nameService.getName();
  }

  function nameService1() {
    return {
      getName: getName
    };

    function getName() {
      return 'First Definition';
    }
  }

  function nameService2() {
    return {
      getName: getName
    };

    function getName() {
      return 'Second Definition';
    }
  }
})();

At runtime, AngularJS will use the value returned by the second implementation of the service: "Second Definition". Please check the this Plunker example.

So, empirically, AngularJS seems to use always the latest definition of a service, ignoring the previous ones.

My question is: is there any official documentation describing this behavior?

Andrea
  • 3,370
  • 1
  • 17
  • 25
  • 3
    Javascript compiles sequentially, hence when it encounters the 2nd nameService, it is overrides the previous one – aliasav Oct 26 '16 at 09:56
  • Well, JavaScript can compile sequentially but it's the Angular framework which decide what to do when it find a second definition of an already defined service. It could, for example, decide to keep always the first instance and discard the others but, at the contrary, it seems to keep always the last one. My question is: is there any official documentation about this behavior? – Andrea Oct 26 '16 at 10:08

4 Answers4

1

Here, you are overwriting definition of factory/service. factory/service is singleton i.e. there will be only one instance of it.

factory('name', constructing_function)

Your case,

factory('nameService', nameService1)//Here object { getName: getName } will be assigned to nameService instance.

factory('nameService', nameService2)//Here object { getName: getName } (#2nd definition) will be assigned to nameService instance. i.e. nameservice instance referring to (#2nd definition).
ram1993
  • 979
  • 1
  • 9
  • 13
  • Thank you for your answer. I know service are singleton in AngularJS but I need to know if there is official Angular documentation which says "Angular always take the latest definition, ignoring the previous ones". Do you know if there is this kind of sentence in the doc? – Andrea Oct 26 '16 at 09:51
  • Don't think so. But I explained what is actually happening behind the seance. – ram1993 Oct 26 '16 at 09:57
  • Yes, thank you Ram1993. But Technically I know it but I need some sort of "official reference" (in documentation, how-tos, etc) of this behavior. – Andrea Oct 26 '16 at 10:06
  • @Andrea So seems like all you have to do is read all the documentation for angularjs and find that reference? Why would you need help from stackoverflow to do that? – Bob Brinks Oct 26 '16 at 12:58
  • Because I did not find any reference in the official documentation about this "feature" and I asked here for any advice. Technically I understand the behavior. – Andrea Oct 26 '16 at 13:00
  • Well the best advice is to go through all the documentation to find this reference. If you already did that and did not find any reference then it's not documented. I still don't see how this is a valid stackoverflow question. – Bob Brinks Oct 26 '16 at 13:02
1

That's the way how JavaScript works:

function Vinoth(){console.log("Printing first")}

function Something(){console.log("Printing Something")}

function Vinoth(){console.log("Printing Second")}

When you do a console.log(Vinoth());, it would always print the Second one. Over to your second part:

  angular
    .module('myApp', [])
    .controller('MainController', MainController)
    .factory('nameService', nameService1)
    .factory('nameService', nameService2);

AngularJS services are singleton by nature, so its going to be one instance across your application life cycle. Your nameService1 and nameService2 are pointing to same nameService instance. Technically it nameService holds nameService2 as it precedes according to hoisting.

Thalaivar
  • 23,282
  • 5
  • 60
  • 71
  • Well, as I explained to "aliasav" in the comment above: the Angular framework which decide what to do when it find a second definition of an already defined service. It could, for example, decide to keep always the first instance and discard the others but, at the contrary, it seems to keep always the last one. My question is: is there any official documentation about this behavior? – Andrea Oct 26 '16 at 10:10
  • @Andrea: Cool, look into the JavaScript Hoisting.... That's the behavior Angularjs Follows too... – Thalaivar Oct 26 '16 at 10:12
  • thanks for the advice, but I do not get why you think is a metter of Hoisting here. In my snippet of code the two functions have different names (`nameService1` and `nameService2`). Only the string identify the service name in `factory()` method is the same (`"nameService"`). – Andrea Oct 26 '16 at 10:16
  • 1
    Thank you @Thalaivar but it does not help. It does not answer my question : "is there any official documentation describing this behavior?". I technically know why AngularJS is behaving this way and it is not a matter of hoisting, please check [method `provider` of `injector.js`](https://github.com/angular/angular.js/blob/v1.4.7/src/auto/injector.js#L674) and you will see that AngularJS simply overwrite the chached service definition in `providerCache` with the latest one. This is the reason why Angualr behaves in this way. But this explanation does not answer my question ;) – Andrea Oct 26 '16 at 12:54
  • @Andrea: look at this thread... http://stackoverflow.com/questions/14909474/namespacing-services-in-angularjs – Thalaivar Oct 26 '16 at 12:58
0

No there is no official documentation for this function.

If you would like there to be you can ask the maintainers of angularjs to add documentation for this feature.

Bob Brinks
  • 1,372
  • 1
  • 10
  • 19
0

Don't need to define the service (Inject) two times. Better solution is , you define the service one time. And use like,

angular.module('myApp', []).controller('MainController', MainController) .factory('nameService', nameService1)

Inside this , we can use that service like,

var nameService2 = angular.copy(nameService);

This is for best practice.

Satzz
  • 57
  • 2
  • 8