14

How to access an instance of root Angular 2 injector globally (say, from browser console).

In Angular 1 it was angular.element(document).injector().

It can be useful during testing and exploration, to use browser console to get injector to then access instances of different components, directives, services etc.

Max Koretskyi
  • 101,079
  • 60
  • 333
  • 488
Ivan
  • 1,552
  • 1
  • 16
  • 25

3 Answers3

19

You must set it into a service after bootstrapping the application:

export var applicationInjector: Injector;

bootstrap([AppComponent]).then((componentRef: ComponentRef) => {
  applicationInjector = componentRef.injector;
});

Then you can import it into other parts of your application:

import {applicationInjector} from './bootstrap';

See this question for more details:

Edit

You can inject the ApplicationRef into components and have access to the root injector through it:

@Component({
  (...)
})
export class SomeComponent {
  constructor(private app:ApplicationRef) {
    var rootInjector = app.injector;
  }
}

You need to leverage dependency injection to get it.

Community
  • 1
  • 1
Thierry Templier
  • 198,364
  • 44
  • 396
  • 360
  • Is the instance of `ComponentRef` saved anywhere by Angular 2 and available globally (something like for example `ng.core.rootComponent()`)? In any case saving it manually is more work than what was available in Angular 1, but is still fine. – Ivan Apr 06 '16 at 15:44
  • For the root component I don't think. That being said you can inject the `ApplicationRef` into your component and get access to the root injector. No need to save it manually ;-) I updated my answer accordingly. – Thierry Templier Apr 06 '16 at 15:55
  • 4
    In current Angular (2.4.4) ```ApplicationRef``` does not have a public property ```injector```; apparently it was made private. – willydee Jan 23 '17 at 12:05
  • @willydee, check [my answer](http://stackoverflow.com/a/43593211/2545680) for the newest version – Max Koretskyi Apr 24 '17 at 16:23
  • @RPDeshaies, check [my answer](http://stackoverflow.com/a/43593211/2545680) for the newest version – Max Koretskyi Apr 24 '17 at 16:23
  • @ThierryTemplier, check [my answer](http://stackoverflow.com/a/43593211/2545680) for the newest version – Max Koretskyi Apr 24 '17 at 16:23
  • Wow, no more `ReflectiveInjector` or `StaticInjector` headaches. Thanks! – Arg0n Jun 26 '18 at 14:12
16

In Angular v.4.x.x the root injector is located on the PlatformRef. You can access it like this:

import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';

// create a platform    
let platform = platformBrowserDynamic();

// save reference to the global object
window['rootInjector'] = platform.injector;

// boostrap application
platform.bootstrapModule(AppModule);

Or inside any component like this:

export class AppComponent {
  constructor(platform: PlatformRef) {
      console.log(platform.injector);

But the root injector is pretty useless. It contains mostly compiler and platform specific data and helpers:

[
  "InjectionToken Platform ID",
  "PlatformRef_",
  "PlatformRef",
  "Reflector",
  "ReflectorReader",
  "TestabilityRegistry",
  "Console",
  "InjectionToken compilerOptions",
  "CompilerFactory",
  "InjectionToken Platform Initializer",
  "PlatformLocation",
  "InjectionToken DocumentToken",
  "InjectionToken Platform: browserDynamic",
  "InjectionToken Platform: coreDynamic",
  "InjectionToken Platform: core"
]

You're probably looking for AppModule injector which you can get like this:

platform.bootstrapModule(AppModule).then((module) => {
  window['rootInjector'] = module.injector;
});

You can extract ApplicationRef or root ComponentRef from it:

platform.bootstrapModule(AppModule).then((module) => {
  let applicationRef = module.injector.get(ApplicationRef);
  let rootComponentRef = applicationRef.components[0];
});

Also, if Angular is running in the development mode, you can get either AppModule or lazy loaded NgModule injector like this:

ng.probe($0).injector.view.root.ngModule
Max Koretskyi
  • 101,079
  • 60
  • 333
  • 488
  • 4
    `ng.probe($0).injector.view.root.ngModule` this way you can get either `AppModule` or lazy loaded `NgModule` injector – yurzui Apr 24 '17 at 16:31
  • @yurzui, yes, but only if not `enableProdMode()` – Max Koretskyi Apr 24 '17 at 16:34
  • He asked `It can be useful during testing and exploration` so it would be helpful :) – yurzui Apr 24 '17 at 16:35
  • @yurzui, yeah, thanks, I'll add to the answer. I've also found an amazing way to subscribe to application bootstrap process :). I'll write an article about it – Max Koretskyi Apr 24 '17 at 16:36
  • @yurzui, thanks for the links, interesting. It seems I got it right with hierarchy of injectors :) – Max Koretskyi Apr 24 '17 at 16:41
  • But beetween elInjectors there are router-outlet injectors :) So my schema is not full – yurzui Apr 24 '17 at 16:44
  • @yurzui, I'll take a look, thanks. I was thinking about writing about injector hierarchy. Whose presentations are these? – Max Koretskyi Apr 24 '17 at 16:46
  • @yurzui, I requested access. Judging by the name on the presentation you seem to be speaking Russian. Do you? – Max Koretskyi Apr 24 '17 at 16:53
  • Yes i do. I gave the access – yurzui Apr 24 '17 at 16:55
  • @yurzui, yeah, quite a lot :) what country? try mine `live:m.koretskyi` – Max Koretskyi Apr 24 '17 at 17:12
  • Is using `bootstrapModule(AppModule).then()` to get a global reference to the AppModule injector not a bit late? The application will have been loaded at this stage - so any calls to `window['rootInjector']` during startup will fail. I used `AppModule constructor` with injected `Injector`, and set that as the global. Is that an equivalent solution, or am I missing something? – Drenai Aug 24 '18 at 11:35
  • @Drenai, can you set up a demo on stackblitz? I'll take a look – Max Koretskyi Aug 29 '18 at 09:29
  • @AngularInDepth.com I've tested it already. The `AppModule` and `AppComponent` constructors are called before `bootstrapModule promise` resolves - so too late to use for global injector. We can use the AppModule constructor to set the global `injector` instance, or the APP_INITIALIZER process. Here's a demo of AppModule approach (with console logs to show same instance of DemoService being provided) https://stackblitz.com/edit/angular-2jwz4p – Drenai Aug 29 '18 at 10:53
2

Here is another take for Angular 9.

Open the JavaScript console on the page of your Angular application that is not in the production node.

Find the <app-root> on the page:

root = document.querySelector("app-root");

Get the injector. The ng() helper is a global that is available if the app is in development mode:

injector = ng.getInjector("app-root");

Injector would allow you to get services by their class name. Unfortunately, I do not know if or how Angular service classes are available through the window namespace.

So our next attempt is to get services from the components of the already visible elements on the page.

appComponent = ng.getComponent(root)

This way you get access to any AppComponent variables e.g. "UserService" your app might have.

appComponent.userService
UserService {http: HttpService, userSubject: BehaviorSubject}

Now you can call the service from the console:

appComponent.userService.userSubject.value.userEmail
mikko@capitalgram.com

You can also access components that are not the application root, and get access to services bound to them. First we need to navigate to the page where the component appears. This will trigger the actual transition in the UI.

await appComponent.router.navigate(["/another-page"])

Now you can get hold of any visible component by its tag name:

elem = document.querySelector("app-my-component")
component = ng.getComponent(elem)

And you can see its services:

MyComponent(envService, http, sanitizer);

And you can poke them, with all your user tokens, sessions, etc. in place:

component.envService.getConfigValue()
Mikko Ohtamaa
  • 82,057
  • 50
  • 264
  • 435