Skip to content
This repository has been archived by the owner on Apr 12, 2024. It is now read-only.

AngularJS config block causes unknown provider error if provider is added to module after the config block #7139

Closed
thebigredgeek opened this issue Apr 16, 2014 · 8 comments

Comments

@thebigredgeek
Copy link
Contributor

This was discussed in IRC at around 1:30-2:00 PM pacific on 04/16/2014 with @caitp

Test case is here https://github.com/thebigredgeek/provider-test-case

Essentially, the config block throws an error, killing the tests. For some reason, however, no error is thrown when injecting the provider in the test using the module() method.

Any help or guidance here would be much appreciated. I am hoping I am simply missing something super obvious.

@caitp
Copy link
Contributor

caitp commented Apr 16, 2014

I was mistaken when I said that it should work already, config blocks and providers are added to the invoke queue in the order that they're called. This is a bug, in my opinion.

It should be easy to fix, although it might mean adding a separate invoke queue for config blocks in order to avoid breaking changes. Just waiting to hear if it's actually desirable or if the current behaviour should remain

For a workaround without the patch, since the order does matter, then yes, if you need to ensure that the config blocks are run after all providers are registered with DI, you should register the config blocks at the very end.

caitp added a commit to caitp/angular.js that referenced this issue Apr 17, 2014
This change ensures that a module's config blocks are always invoked after all of its providers are
registered.

BREAKING CHANGE:

Previously, config blocks would be able to control behaviour of provider registration, due to being
invoked prior to provider registration. Now, provider registration always occurs prior to configuration
for a given module, and therefore config blocks are not able to have any control over a providers
registration.

Example:

Previously, the following:

   angular.module('foo', [])
     .provider('$rootProvider', function() {
       this.$get = function() { ... }
     })
     .config(function($rootProvider) {
       $rootProvider.dependentMode = "B";
     })
     .provider('$dependentProvider', function($rootProvider) {
       if ($rootProvider.dependentMode === "A") {
         this.$get = function() {
           // Special mode!
         }
       } else {
         this.$get = function() {
           // something else
         }
       }
     });

would have "worked", meaning behaviour of the config block between the registration of "$rootProvider"
and "$dependentProvider" would have actually accomplished something and changed the behaviour of the
app. This is no longer possible within a single module.

Fixes angular#7139
@caitp
Copy link
Contributor

caitp commented Apr 17, 2014

i still haven't heard whether or not it's desirable to let config blocks have a role in controlling the way providers are actually registered.

But I'm not totally convinced that they should play such a role, so yeah

caitp added a commit to caitp/angular.js that referenced this issue Apr 17, 2014
This change ensures that a module's config blocks are always invoked after all of its providers are
registered.

BREAKING CHANGE:

Previously, config blocks would be able to control behaviour of provider registration, due to being
invoked prior to provider registration. Now, provider registration always occurs prior to configuration
for a given module, and therefore config blocks are not able to have any control over a providers
registration.

Example:

Previously, the following:

   angular.module('foo', [])
     .provider('$rootProvider', function() {
       this.$get = function() { ... }
     })
     .config(function($rootProvider) {
       $rootProvider.dependentMode = "B";
     })
     .provider('$dependentProvider', function($rootProvider) {
       if ($rootProvider.dependentMode === "A") {
         this.$get = function() {
           // Special mode!
         }
       } else {
         this.$get = function() {
           // something else
         }
       }
     });

would have "worked", meaning behaviour of the config block between the registration of "$rootProvider"
and "$dependentProvider" would have actually accomplished something and changed the behaviour of the
app. This is no longer possible within a single module.

Fixes angular#7139
@thebigredgeek
Copy link
Contributor Author

Thanks @caitp Sorry about the fragmented questions I was moving from computer to laptop quite a bit and for some reason I kept missing messages.

@thebigredgeek
Copy link
Contributor Author

you could just defer execution of config blocks by making them async (step n) (so that the entire context can resolve BEFORE the config blocks execute), but then you would also need to make the initial compile n + 1 (timeout AFTER injector, which should be fine since timeouts are FIFO).

@thebigredgeek
Copy link
Contributor Author

also... how is module() in angular-mocks injecting providers? Because that implementation works fine. Are we not injecting providers by passing through to angular.module(...).config with angular-mocks? If we were, that behavior (the error case) should have been presented before I used a config block within the source code of the test case listed above.

@caitp
Copy link
Contributor

caitp commented Apr 17, 2014

@thebigredgeek angular.mock.module() doesn't use the loader api itself, however if you're saying beforeEach(module('myApp')), then your app's providers will be added to the injector. They would have been originally added via the loader api in your app. Anyways, doing it this way, there would be no problem running your config method because it would be added after the providers were already there.

@toota151
Copy link

7139

@toota151
Copy link

Goood

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants