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

An $injector that is instantiated in the configure stage will not be able to inject run services in the run stage #5559

Closed
KevinBrogan opened this issue Dec 29, 2013 · 10 comments

Comments

@KevinBrogan
Copy link
Contributor

Problem:

I want to access run time services within $httpProvider.defaults.transformResponse[] functions.

These functions are not injectable, yet they are only configurable in the config stage, yet they are only executed in the run stage.

So as an example, let's say I want to access $rootScope within a transformResponse function.

module.config(function($httpProvider,$injector)
{
    $httpProvider.defaults.transformResponse.push(function(data)
    {
        // Unknown provider: $rootScope
        $injector.get('$rootScope')';

        // Unknown provider: $rootScope
        $injector.invoke(function($rootScope){});
    });
}

Even though the injector is being called from within the run stage, I'm not able to access run time services.

Instead, I have to use this kludge.

var runInjector = null;

module.run(function($injector)
{
    runInjector = $injector;
})
.config(function($httpProvider)
{
    $httpProvider.defaults.transformResponse.push(function(data)
    {
        // Success
        runInjector .get('$rootScope')';
    });
}
@MikeMcElroy
Copy link
Contributor

You can access run-time services on $http.defaults, using module.run. See http://plnkr.co/edit/1MwiSIbFOUdEI5rvzZBP?p=preview

but basically, the code would look something like:

module.run(function($http,$injector)
{
    $http.defaults.transformResponse.push(function(data)
    {
        // Valid provider: $rootScope
        $injector.get('$rootScope')';

        // Valid provider: $rootScope
        $injector.invoke(function($rootScope){});
    });
}

@KevinBrogan
Copy link
Contributor Author

Ah excellent. Thank you. Searching for .defaults in the documentation, I found a tiny section that mentions this, but under the heading that has to do with headers, which I had no interest in changing and so did not read.

There are two mentions of $http.defaults (one under headers and one under caching) and 16 mentions of $httpProvider.defaults. Easy to see how I missed that...

Still, the injector behavior doesn't make any sense.

@MikeMcElroy
Copy link
Contributor

It actually does, though. In the config function, $injector is the
provider injector, where in the run function, $injector is the instance
injector. $rootScope does not exist in the provider injector, but
$rootScopeProvider does.
On Dec 28, 2013 11:36 PM, "Kevin Brogan" notifications@github.com wrote:

Ah excellent. Thank you. Searching for .defaults in the documentation, I
found a tiny section that mentions this, but under the heading that has to
do with headers, which I had no interest in changing and so did not read.

There are two mentions of $http.defaults (one under headers and one under
caching) and 16 mentions of $httpProvider.defaults. Easy to see how I
missed that...

Still, the injector behavior doesn't make any sense.


Reply to this email directly or view it on GitHubhttps://github.com//issues/5559#issuecomment-31311883
.

@KevinBrogan
Copy link
Contributor Author

They aren't called $providerInjector and $instanceInjector, just $injector and $injector. Every other provider/instance or config/run dichotomy in angular, is separated with variant function or object names. The documentation on $injector doesn't mention that there are two separate injectors.

The injector is supposed to be the single source of truth for dependency injection, so to me, no, it does not make any sense for any angular component to be providing config services during the run phase.

@MikeMcElroy
Copy link
Contributor

But one's the $injector at the config stage (only providers and constants accessible), and one's the $injector at the run stage. The confusion may be that you're thinking the $injector modifies itself to include the new stuff as it crosses the line from config to run, but that's not true. They're two separate (although related) objects, with their own caches of instances.

More to the point, your config function was defining the transformResponse function within itself, so the $injector value being used was the config-time $injector (by lexical scoping), and $rootScope did not exist at config-time.

A more in-depth reason for this dichotomy will probably come from a deep learning of the $injector internals, but it seems like it's been DRY-ed pretty hardcore, and the two types of injectors share almost all the same behavior, except in how they deal with "cache misses" in their instance caches.

@KevinBrogan
Copy link
Contributor Author

Well, the documentation threw me off originally, but there's no confusion
anymore. Thanks Mike.

I still think the two injectors should be named as separate objects.

@ghost ghost assigned IgorMinar Jan 4, 2014
@IgorMinar
Copy link
Contributor

we are going to overhaul the injector in v2, so this will get fixed there (getting rid of the config phase is one of the objectives of the injector v2).

in the meantime, could you guys send us a PR with an update to the documentation that would make it easier for folks with use-case like yours to solve the issue via $http.defaults.

thanks!

@MikeMcElroy
Copy link
Contributor

Sure, I'll look into getting something submitted in the morning.

MikeMcElroy added a commit to MikeMcElroy/angular.js that referenced this issue Jan 4, 2014
…time

Clarifies some confusion around $http.defaults existing and able to be modified
at run-time, for when run-time services may be needed in a transformation.

Closes angular#5559
MikeMcElroy added a commit to MikeMcElroy/angular.js that referenced this issue Jan 4, 2014
…time

Clarifies some confusion around $http.defaults existing and able to be modified
at run-time, for when run-time services may be needed in a transformation.

Closes angular#5559
@MikeMcElroy
Copy link
Contributor

Or I'll just do it now. :-)

@KevinBrogan
Copy link
Contributor Author

Awesome guys. :-D

jamesdaily pushed a commit to jamesdaily/angular.js that referenced this issue Jan 27, 2014
…time

Clarifies some confusion around $http.defaults existing and able to be modified
at run-time, for when run-time services may be needed in a transformation.

Closes angular#5559
Closes angular#5630
jamesdaily pushed a commit to jamesdaily/angular.js that referenced this issue Jan 27, 2014
…time

Clarifies some confusion around $http.defaults existing and able to be modified
at run-time, for when run-time services may be needed in a transformation.

Closes angular#5559
Closes angular#5630
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants