Overcoming the AngularJS singleton service limitation

As a general rule, Angular services are singletons.
But every once in a while, you need a service that is a new instance every time it is injected.

This can be accomplished by returning a factory function instead of an object:

angular.module('myApp.Services')
.factory('mySrv', ['', function() {
   
   function serviceFactory(conf) {
    // logic...
        return serviceInstance;
   }

   return serviceFactory;

}]);

This basically means, that each time the service is injected, what is actually being injected is the factory function. 
This allows for calling var instance = mySrv(conf) and getting a new instance.
The $resource service is implemented like this.

Great! Now we get a new instance each time the service is injected! Yeepee! :)

BUT! (there's always a 'but', isn't there?)
what if you want to get a new instance SOME OF THE TIME?
What I mean is, that based on some configuration and business logic, you want to be able to decide if you want to return a new instance or reinject an existing one. 

This is an extension of the previous example.

angular.module('myApp.Services')
.factory('mySrv', ['', function() {

    function serviceFactory(instanceName) {
    //do some tests and recover or throw error
        
        return getInstance(instanceName);
    }

    function getInstance(instanceName) {
        if (!instancesMap.hasOwnProperty(instanceName)) {
            createServiceInstance(instanceName);
        }

        return instancesMap[instanceName];
    }

    function destroyInstance(instanceName) {
        if (instancesMap.hasOwnProperty(instanceName)) {
            delete instancesMap[instanceName];
        }
    }

    function createServiceInstance(instanceName) {
        var service = {
            //this is important since without it you might get memory leaks.
            destroyInstance: function(instanceName) {
                destroyInstance(instanceName);
            },
           //add service api here ...


        };

        instancesMap[instanceName] = service;
    }

    return serviceFactory;
    
}]);

This is a naive implementation just to make a point, but it will allow us to use it as a singleton (if we only use a single instance name) or any number of instances as it fits the business logic. All that needs to be done is pass a configuration object instead of the instanceName and do some business logic with it in the getInstance function to determine if it should return a new instance or an instance previously stored in the instancesMap.

Fullstack Architect

Frontend Group

Thank you for your interest!

We will contact you as soon as possible.

Want to Know More?

Oops, something went wrong
Please try again or contact us by email at info@tikalk.com
Thank you for your interest!

We will contact you as soon as possible.

Let's talk

Oops, something went wrong
Please try again or contact us by email at info@tikalk.com