3

Because every service is a singleton. & calling $injector.get() still gives me the same instance everytime.

How can I use multiple instances of a service inside another service? Keeping in mind that the declaration of my non-singleton class, must not pollute the global namespace etc.

My example is below: (Where I wanted $injector.get('serviceCall') to be a different instance everytime, but I've since discovered it can't be.

app.factory('reportsService', ['$injector', function ($injector) {
    var o = {};
    o.getServiceCall = function () {
        return $injector.get('serviceCall');
    };
    o.getOriginCompositionData = function (ajaxOptions) {
        ajaxOptions.url = '/test/SpiderRequestOriginComposition';
        o.getServiceCall().initialize(ajaxOptions);
    };
    o.getExeuctionTimeData = function (ajaxOptions) {
        ajaxOptions.url = '/test/SpiderRequestExeuctionTime';
        o.getServiceCall().initialize(ajaxOptions);
    };
    o.getCacheCompositionData = function (ajaxOptions) {
        ajaxOptions.url = '/test/SpiderRequestCacheComposition';
        o.getServiceCall().initialize(ajaxOptions);
    };
    return o;
}]);

and my serviceCall Service:

app.factory('serviceCall', function () {
    var o = {};
    o.initialize = function (userOptions) {
        o.options = o.getOptions(userOptions);
        o.call();
    };
    o.getOptions = function (userOptions) {
        var defaultOptions = {
            action: 'post',
            url: '', //userOptions
            successCallback: '', //userOptions
            errorCallback: '', //userOptions
            dataType: 'json'
        };
        var options = $.extend(defaultOptions, userOptions);
        return options;
    };
    o.call = function () {
        $.ajax({
            type: o.options.action,
            url: o.options.url,
            data: o.options.data,
            success: function (r) {
                o.options.successCallback(r);
            },
            error: function (xhr, textStatus, errorThrown) {
                //TODO
            },
            dataType: o.options.dataType,
            contentType: o.options.contentType
        });
    };
    return o;
});

2 Answers 2

5

You'll need to implement the factory pattern. Return a service that creates object instances for you. $injector.get('serviceCall') will always return a singleton, but there's nothing stopping you making that singleton's job generating new object instances for you.

Rather than using $injector, directly DI a serviceCallFactory service, and call methods on that to generate the new serviceCall instances.

Sign up to request clarification or add additional context in comments.

Comments

3

Agree with @eddiec.

The thing is, when you're new to angular, you suppose factory is like the design pattern Factory : a function that provides a new instance at each call. However, 'factory' in angular is actually a function that is called only one time and that returns an object that will be "cached". Now, every time you DI with the factory name, this object will be injected, not the factory function.

So, if you want a "real" (the design pattern) Factory, you need to create a function that returns a new object.

Here is a quick implementation

app.factory('serviceCallFactory', function () {

    function o() {
        var o = {};
        o.initialize = function (userOptions) {
            o.options = o.getOptions(userOptions);
            o.call();
        };
        o.getOptions = function (userOptions) {
            var defaultOptions = {
                action: 'post',
                url: '', //userOptions
                successCallback: '', //userOptions
                errorCallback: '', //userOptions
                dataType: 'json'
            };
            var options = $.extend(defaultOptions, userOptions);
            return options;
        };
        o.call = function () {
            $.ajax({
                type: o.options.action,
                url: o.options.url,
                data: o.options.data,
                success: function (r) {
                    o.options.successCallback(r);
                },
                error: function (xhr, textStatus, errorThrown) {
                    //TODO
                },
                dataType: o.options.dataType,
                contentType: o.options.contentType
            });
        };
        return o;
    }

    return {
        create : function () {
            return new o();
        }
    }

});


app.factory('reportsService', ['serviceCallFactory', function (serviceCallFactory) {
    var o = {};
    o.getServiceCall = function () {
        return serviceCallFactory.create();
    };
    o.getOriginCompositionData = function (ajaxOptions) {
        ajaxOptions.url = '/test/SpiderRequestOriginComposition';
        o.getServiceCall().initialize(ajaxOptions);
    };
    o.getExeuctionTimeData = function (ajaxOptions) {
        ajaxOptions.url = '/test/SpiderRequestExeuctionTime';
        o.getServiceCall().initialize(ajaxOptions);
    };
    o.getCacheCompositionData = function (ajaxOptions) {
        ajaxOptions.url = '/test/SpiderRequestCacheComposition';
        o.getServiceCall().initialize(ajaxOptions);
    };
    return o;
}]);

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.