66

Can I get a list of all registered directives, services, controllers, etc. at runtime . . . ?

Brian H.
  • 854
  • 8
  • 16
blaster
  • 8,876
  • 11
  • 48
  • 77
  • Possible duplicate of [List declared directives/controllers in AngularJS module](http://stackoverflow.com/questions/18986870/list-declared-directives-controllers-in-angularjs-module) – Krzysztof Safjanowski Oct 26 '16 at 10:02

4 Answers4

66

You can get a list of the providers (ie services/directives/controllers/factories/etc) for each module, although the list is kind of cryptic.

Say you have the following:

var mod = angular.module('myModule', []);
mod.factory('fact1', function($dependency1, $dependency2){ ... });
mod.service('serv1', function($dependency3, $dependency4){ ... });
mod.controller('ctrl1', function($dependency2, $dependency3){ ... });
mod.factory('fact2', function($dependency1, $dependency4){ ... });
...

Then the mod variable will contain an attribute called mod._invokeQueue that will contain an array of all the providers that are part of that module. The _invokeQueue will look something like this:

[
    ['$provide', 'factory', Arguments['fact1', ['$dependency1', '$dependency2', function(){}],
    ['$provide', 'service', Arguments['serv1', ['$dependency3', '$dependency4', function(){}],
    ['$provide', 'controller', Arguments['ctrl1', ['$dependency2', '$dependency3', function(){}],
    ['$provide', 'factory', Arguments['fact2', ['$dependency1', '$dependency4', function(){}]
    ...
]

So you can search through that mod._invokeQueue for each provider that it contains.

But that will only contain the list of providers for that specific module. If you want to get a list of all of the dependent modules, you will need to loop through the mod.requires array.

If the module has module-level dependencies, like so:

var mod = angular.module('myModule', ['otherModule1','otherModule2']);

Then the mod object will also have a mod.requires array that contains the names of those module dependencies, like so:

angular.forEach(mod.requires, function(requiredModuleName){
    // first get a reference to the required module by calling angular.module()
    var requiredMod = angular.module(requiredModuleName);
    // requiredMod will have its own ._invokeQueue
    // requiredMod._invokeQueue will look like the _invokeQueue from above
    ...
    // do something with the additional providers in _invokeQueue
});
starball
  • 20,030
  • 7
  • 43
  • 238
tennisgent
  • 14,165
  • 9
  • 50
  • 48
  • 3
    Thank you! Very helpful. I wish Angular just exposed some metadata about itself in a kinder way - getServices(), etc. – blaster Oct 18 '13 at 15:58
  • If I do `var mod = angular.module('myModule');...` from Chrome dev's console when the app runs, it doesn't show anything in the array. Is this supposed to be in the .js code itself and not runtime? – HP. Jan 03 '14 at 07:53
  • Yeah, you can't modify a module once it has been loaded (as far as I know), so you'd have to do some sort of console logging or something to see what is inside (such as adding a `console.log()` statement right after the module is declared in the code) – tennisgent Jan 07 '14 at 03:05
  • 8
    Actually you can. You can register new modules/controllers etc directly in the console of Chrome and even from IE or any other browser that supports a console. If you type in the console angular.module('myApp')._invokeQueue you will see the array of all registered components. – GxG Mar 10 '14 at 13:15
  • 1
    I stand corrected. Apparently you can modify a module on the fly. Thanks to @GxG for the clarification. – tennisgent Jun 06 '14 at 15:05
  • is there any way to retrieve the actual object of the service/factory etc.? I see this returns the name, dependancies and creator function but can I use it to get the cached object (once instantiated by angular)? – Luke Deighton Oct 09 '14 at 10:47
  • @LukeDeighton, I'm not sure what you mean by "the actual object" or the "cached object"? What are you trying to accomplish? – tennisgent Oct 09 '14 at 15:00
  • I'm trying to get the factory object, where you do: app.factory('myFactory', function() { return {} <--- this thing here }); Edit: http://stackoverflow.com/questions/26276183/angularjs-retrieve-factory-object-at-runtime-dynamically – Luke Deighton Oct 09 '14 at 15:18
  • Really interesting! Anyone know if there is any way to read all the methods in $resource that I retrieve in that method? – teone Jun 11 '15 at 15:47
  • @teone, what do you mean? Why would you want to read all the methods in `$resource`? – tennisgent Jun 11 '15 at 19:17
  • I was wondering if I could dinamically generate decorators for all the $resource service attached to my application, as I would like to add a caching system, then I realized that $http has his own cache method... So it's not needed anymore, but is still interesting... – teone Jun 12 '15 at 12:40
43

Try this:

angular.module('MyApp')['_invokeQueue'].forEach(function(value){ 
    console.log(value[1] + ": " + value[2][0]);
})
32

Here's how you can get most services

Ie: constants, values, factories, services.

    function allServices(mod, r) {
      var inj = angular.element(document).injector().get;
      if (!r) r = {};
      angular.forEach(angular.module(mod).requires, function(m) {allServices(m,r)});
      angular.forEach(angular.module(mod)._invokeQueue, function(a) {
        try { r[a[2][0]] = inj(a[2][0]); } catch (e) {}
      });
      return r;
    };

    allMyServices = allServices('myApp');

Now when you type in the console allMyServices. you'll get an auto-complete list of them.


The function above can fail in certain situations where angular.element(document).injector() returns undefined. You can use the function below instead...


Alternate Method

    var inj;
    function allServices(mod, r) {
      if (!r) {
        r = {};
        inj = angular.element(document.querySelector('[ng-app]')).injector().get;
      }
      angular.forEach(angular.module(mod).requires, function(m) {allServices(m,r)});
      angular.forEach(angular.module(mod)._invokeQueue, function(a) {
        try { r[a[2][0]] = inj(a[2][0]); } catch (e) {}
      });
      return r;
    };

    allMyServices = allServices('myApp');

Now when you type in the console allMyServices. you'll get an auto-complete list of them.


Note: With either method, be sure to replace 'MyApp' with your module name.

Gil Birman
  • 35,242
  • 14
  • 75
  • 119
  • 1
    `allMyServices = allServices(document.querySelector('[ng-app]').getAttribute('ng-app'));` – Mark Rajcok Mar 01 '15 at 03:56
  • 1
    This can still potentially fail if the app was loaded with [angular.bootstrap()](https://docs.angularjs.org/api/ng/function/angular.bootstrap), in which case my favorite thing to do when I need an injector is grab the first element with the `ng-scope` class, since any element within an app will return the same injector: `angular.element('.ng-scope').injector();` – Ken Bellows Apr 05 '16 at 20:59
  • The autocomplete is golden. – ProgrammerGuy Jan 03 '17 at 20:01
  • To access the property of a specific module, your answer helped me come up with this: `angular.element(document.querySelector('[ng-app]')).injector().get(Modules.YourModuleId).yourProperty` – nitzel Dec 01 '17 at 12:27
0

I've created a GitHub gist with some code that can output the dependencies in a Graphviz friendly format. Which means you should be able to visualize the dependency graph.

See https://gist.github.com/dlidstrom/a2f787cef41ea4fcb8aa74d459f49270.

Daniel Lidström
  • 9,930
  • 1
  • 27
  • 35