Create injectable class (constructor)

14,696

Solution 1

You're quite right, this is the way to create injectable "classes" (constructors). However, using factory is only necessary when you need to inject other stuff to be used by your class:

.factory('Class', ['$q', function ($q) {
    function Class () {}
    Class.prototype = {
        constructor: Class,
        doSomeAsyncAction: function () {
            return $q(function (resolve, reject) {
                // ...
            });
        },
        // ...
    };
    return Class;
})

If you're creating a completely independent class (e.g. some data structure), you can just use constant, so that your class is available even in service providers:

(function (undefined) {
    function Class () {}
    Class.prototype = { ... };
    angular.module(...)
        .constant('Class', Class);
})();

As a sidenote, using provider is not going to help you in this. Providers serve a completely different purpose and (among other things) return a factory function that is then used _once_ on the first requested injection to create a single instance of the service. Providers are used to let you configure that single service instance in the _config phase_ of application construction (see documentation).

Solution 2

I am having the same problem. Here's what I implemented:

angular.module('foo', [])
.factory('Foo', ['$http', function($http) {
  return function(a, b) {
    this.arr = [];
    this.a = a;
    this.b = b;
    this.random = Math.floor(Math.random()*11);

    this.someFunc = function(c) {
      this.arr.push(c);
    };
  };
}]);

Now, I can do:

var f1 = new Foo('A', 'B');
f1.random;  // i.e. 0
f1.someFunc('z');  // only affects f1.arr
var f2 = new Foo('C', 'D');
f2.random;  // i.e. 8
f2.someFunc('y');  // only affects f2.arr

Makes things more modularized. Hope that helps.

Solution 3

I had the same question. I found a terrific article on how to setup Object-oriented AngularJS Services. Here's the article. Pay attention to the note about using Factories and not Services. It also covers extending your objects. I found it super easy to setup and it fit perfectly with Angular while keeping the Javascript simple and straight forward.

For Factory services which are singletons and do not need to be instantiated I use the object literal approach which has some performance advantages.

Solution 4

Here's how I solved the issue:

(function (myModule) {
    'use strict';

    myModule.service('myService', [
        function() {
            var serivce = this;
            var obj = null;

            service.func1 = function(a, b) {

            }

            service.func2 = function(c, d) {
                . . .
                return something;
            }

            var constructor = function(myObj) {
                obj = myObj;

                return service;
            }

            return constructor;
        }
    ]);
}(angular.module("myModule")))

(function(myModule) {
    'use strict';

    myModule.controller('myController', [
        '$scope', 'myService', function($scope, myService) {

            var service = myService($scope.someObj);

            $scope.someOtherObj = service.func2($scope.a, $scope.b);

        }
    ]);
}(angular.module("myModule")))

The only thing returned from the service is the constructor and then the service returns the rest of the service.

Share:
14,696

Related videos on Youtube

NilsH
Author by

NilsH

Programmer. Mainly Java, but lately also C#, JavaScript and Scala

Updated on September 14, 2022

Comments

  • NilsH
    NilsH over 1 year

    I'm an AngularJS newbie, and I'm just starting to understand the concepts and differences of factory, service and controller. As I understand, a factory is used to return a "value object" that can be injected. Most examples I've seen do something like this:

    angular.module('module.factories', function() {
        factory('FactoryObject', function() {
            return {
                someFunction: function(someParam) {};
                someOtherFunction: function(someOtherParam) {});
            };
        });
    });
    

    In my controller, I want to be able to use this object, but I would like to initialize/instantiate it in the controller, since it can be re-initialized depending on events/actions in the controller. Therefore, I was wondering if I could return a constructor function in the factory instead?

    angular.module('module.factories', function() {
        factory('FactoryObject', function() {
    
            function FactoryObject(initParam) {
            }
    
            FactoryObject.prototype.someFunction = function() {};
    
            return FactoryObject;
    
        });
    });
    

    Is this a suitable pattern for an angular factory? Or is it just "overkill" to use a factory for a custom object like this? Should I just include it in a library js file and reference it from there instead? One benefit of putting it in a factory is that it will be easy to mock it in a test since it will be injected where it's used. Are there any other mechanisms in Angular that could be used instead?