Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Importing multiple AngularJS module's factories

I was wondering if there was a way to import all the factories I've defined in an AngularJS module into a controller without having to list them all. Say I have a file named foo.js containing:

angular.module("Foo", [])
.factory("Bar1", function() {...})
.factory("Bar2", function() {...})
.factory("Bar3", function() {...})
.factory("Bar4", function() {...});

Now, in my controller.js file I have:

angular.module("myApp.controllers", ["Foo"]).
controller("MainCtrl", ["Bar1", "Bar2", "Bar3", "Bar4", function(bar1, bar2, bar3, bar4) {
    //do stuff with the various bars
}]);

I was simply wondering if there's any elegant way for the controller, since it already imports the module Foo, to see all its factories (or providers, or services, or directives as a matter of fact).

like image 887
Andrea Aloi Avatar asked Aug 17 '14 20:08

Andrea Aloi


People also ask

Can we have multiple modules in AngularJS?

Yes, you can define multiple modules in angularJS as given below. The modularization in AngularJS helps us to keep the code clarity and easy to understand, as we can combine multiple modules to generate the application.

What are the differences between AngularJS module's service provider and factory?

provider. Providers have the advantage that they can be configured during the module configuration phase. See here for the provided code. So factory is a function which is responsible for creating the value.

What are AngularJS factories?

What is Factory in AngularJS? Factory is an angular function which is used to return the values. A value on demand is created by the factory, whenever a service or controller needs it. Once the value is created, it is reused for all services and controllers. We can use the factory to create a service.

What is module and controller in AngularJS?

An AngularJS module defines an application. The module is a container for the different parts of an application. The module is a container for the application controllers. Controllers always belong to a module.


1 Answers

Yes, it is possible.

You can dynamically load a module an examine its _invokeQueue field (see https://stackoverflow.com/a/19412176/646543) in order to retrieve the names of all the factories/controllers/etc defined in a module.

You can then use the $injector service to actually retrieve the factories.

To demonstrate, I've created a quick proof-of-demo. You should be able to directly copy-and-paste the IntrospectModule factory into your app to get this functionality.

// Creating some test services
angular.module('test-services', [])
    .factory('Bar1', function() {
        return { 'stuff': function() { return 'calling bar1' } };
    })
    .factory('Bar2', function() {
        return { 'stuff': function() { return 'calling bar2' } };
    });

angular.module('myapp', ['test-services'])
    .factory('IntrospectModule', function($injector) {
        // This factory will dynamically return all services/controllers/directives/etc
        // given the module name.

        return function (moduleName) {
            var out = {};
            angular.module(moduleName)._invokeQueue.forEach(function(item) {
                var name = item[2][0];
                out[name] = $injector.get(name);
            });
            return out;
        };
    })
    .controller('MainCtrl', function($scope, IntrospectModule) {
        // And now I'm using it
        var testServices = IntrospectModule('test-services');
        $scope.test = testServices.Bar1.stuff();
    });

Here's a working plnkr of the above.


Alternatively, if that feels too hacky, you could try creating a 'composite' factory:

angular.module("test-services", [])
    .factory("Bar1", function() {...})
    .factory("Bar2", function() {...})
    .factory("Bar3", function() {...})
    .factory("Bar4", function() {...})
    .factory("EveryBar", ["Bar1", "Bar2", "Bar3", "Bar4", 
        function(bar1, bar2, bar3, bar4) {
            return {
                'bar1': bar1, 
                'bar2': bar2,
                'bar3': bar3,
                'bar4': bar4
            };
        }]);

Then, inside your controllers, do:

angular.module("myApp.controllers", ["test-services"]).
controller("MainCtrl", ["EveryBar", function(everyBar) {
    everyBar.bar1.stuff();
}]);

Obviously, the disadvantage of this approach is that it results in a good deal of redundancy when setting up your services -- we're still manually listing everything.

However, if you need to use the same services multiple times in several different controllers, then creating the composite service would at least allow you avoid having to list a bunch of parameters in every controller.

It's also much more explicit then the first solution, and allows you to cleanly enumerate exactly which services you want rather then mucking around in the internals of Angular, and lets you extend the services, add helper/wrapper functions, etc.

like image 138
Michael0x2a Avatar answered Sep 28 '22 09:09

Michael0x2a