Configuring a Provider

in Front-End Web Technologies

What is wrong with below code ?

angular.module("MyApp", []).config(function (MyProvider) {
});
 
angular.module("MyApp").provider("My", function () {
    this.$get = function () {
        var service = {
            doSomething: function () {
                console.log("Do something ...");
            }
        };
 
        return service;
    }
});

Nothing. But, depends on the version of Angular you are using you might encounter errors.

Running above code with Angular 1.2.9 generates the following error:
Failed to instantiate module MyApp due to unknown provider: MyProvider

Apparently, Angular 1.2.9 queues config callbacks and provider registration requests into the same queue. Lets look at Angular 1.2.9 implementation for a module

function module(name, requires, configFn) {
        var invokeQueue = [];
        var runBlocks = [];

        var moduleInstance = {
            provider: invokeLater('$provide', 'provider'),
            config: invokeLater('$injector', 'invoke'),
        };

        return  moduleInstance;

        function invokeLater(provider, method, im) {
            return function() {
                invokeQueue[im || 'push']([provider, method, arguments]);
                return moduleInstance;
            };
        }
    });
};

A module instance holds two private queues, invokeQueue and runBlocks. Both provider and config methods are using invokeQueue queue

Later, Angular loads the module by walking the queues and invoking all registered callbacks.

Our problematic sample code first registers a config block

angular.module("MyApp", []).config(function (MyProvider) {
});

And only then registers a provider

angular.module("MyApp").provider("My", function () {
    this.$get = function () {
        var service = {
            doSomething: function () {
                console.log("Do something ...");
            }
        };
 
        return service;
    }
});

This means that Angular 1.2.9 first tries to invoke the config block and only then instantiate the provider MyProvider. As result, Angular is not able to resolve the dependency of the config block and generates and error.

BTW, if we change the code a bit it works. Here is a working sample (but somehow strange)

angular.module("MyApp", []);
 
angular.module("MyApp").provider("My", function () {
    this.$get = function () {
        var service = {
            doSomething: function () {
                console.log("Do something ...");
            }
        };
 
        return service;
    }
});
 
angular.module("MyApp").config(function (MyProvider) {
});

See, first we define the module, then register the provider and only then register the config block.

IMHO, this is an Angular bug. All module’s providers must be instantiated before invoking any config block. Else, some config blocks might be broken.

Indeed, Angular version 1.3+ fixes this issue. Let’s look at the new module implementation

function module(name, requires, configFn) {
    var invokeQueue = [];
    var configBlocks = [];
    var runBlocks = [];

    var moduleInstance = {
        provider: invokeLater('$provide', 'provider'),

        config: invokeLater('$injector', 'invoke', 'push', configBlocks),
    };

    return moduleInstance;

    function invokeLater(provider, method, insertMethod, queue) {
        if (!queue) queue = invokeQueue;
        return function () {
            queue[insertMethod || 'push']([provider, method, arguments]);
            return moduleInstance;
        };
    }
}

This time there are 3 queues: invokeQueue, configBlocks and runBlocks.

The provider method queues requests into the invokeQueue queue while the config method queues requests into configBlocks queue

Later, Angular first executes all provider requests registered into the invokeQueue queue and only then it executes the registered config blocks.

I encountered this bug several times in production development and pleased to see that Angular’s guys are improving Angular with respect to small bugs and not just adding big features

Enjoy,

Contact us
You might also like
Share: