Andrei
Andrei

Reputation: 353

Angular Hybrid Error: Trying to get the AngularJS injector before it being set

How to use AngularJS service in Angular 5 component?

I have AngularJS application and i am trying to make hybrid app but not able to use AngularJS service insight Angular component : getting error

ERROR Error: Trying to get the AngularJS injector before it being set.

my main.ts is

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule);

app.module :

import { BrowserModule } from '@angular/platform-browser';
import { NgModule, InjectionToken } from '@angular/core';
import { FormsModule } from '@angular/forms';

import { UpgradeModule, downgradeComponent } from '@angular/upgrade/static';
import { AppComponent } from './app.component';
import { SignInComponent } from "./modules/login/components/sign-in/sign-in.component";
import { authServiceProvider } from './shared/angularJS-upgraded-providers';



@NgModule({
    declarations: [
        AppComponent,
        SignInComponent
    ],
    imports: [
        BrowserModule,
        UpgradeModule,
        FormsModule
    ],
    entryComponents: [
        SignInComponent
    ],
    providers: [authServiceProvider],
    bootstrap: [SignInComponent]
})

export class AppModule {
    ngDoBootstrap() {}
}

angularJS-upgraded-providers.ts :

import { InjectionToken } from "@angular/core";
export const AuthService = new InjectionToken<any>('authService');

export function authServiceFactory(i: any) {
  return i.get('authService');
}

export const authServiceProvider = {
  provide: AuthService,
  useFactory: authServiceFactory,
  deps: ['$injector']
};

and sign-in.component.ts :

import { Component, Inject } from '@angular/core';
import {AuthService} from "../../../../shared/angularJS-upgraded-providers";

@Component({
    selector: 'sign-in',
    template: require('./sign-in.component.html')
})

export class SignInComponent {
    constructor(
        @Inject(AuthService) private authService: any) {
    }
}

When I remove SignInComponent constructor part code compiles well but with @Inject(AuthService) private authService: any) { } part I am getting an error :

Trying to get the AngularJS injector before it being set.

Please give me some suggesting how can I implement angularJS service insight Angular component. Thanks

P.S. my package.json :

{
  "name": "test",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "start": "webpack-dev-server --port=4200 --open chrome"
  },
  "dependencies": {
    "@angular/common": "^5.2.11",
    "@angular/compiler": "^5.2.11",
    "@angular/core": "^5.2.11",
    "@angular/forms": "^5.2.11",
    "@angular/http": "^5.2.11",
    "@angular/platform-browser": "^5.2.11",
    "@angular/platform-browser-dynamic": "^5.2.11",
    "@angular/router": "^5.2.11",
    "@angular/upgrade": "^5.2.11",
    "core-js": "^2.5.7",
    "reflect-metadata": "^0.1.12",
    "rxjs": "^5.5.11",
    "zone.js": "^0.8.26"
  },
  "devDependencies": {
    "@types/jquery": "^3.3.6",
    "@types/node": "^8.10.23",
    "awesome-typescript-loader": "^5.2.0",
    "css-loader": "^1.0.0",
    "html-loader": "^0.5.5",
    "html-webpack-plugin": "^3.2.0",
    "raw-loader": "^0.5.1",
    "style-loader": "^0.22.1",
    "ts-loader": "3.2.0",
    "typescript": "^2.9.2",
    "webpack": "^4.16.5",
    "webpack-cli": "^3.1.0",
    "webpack-dev-server": "^3.1.5"
  }
}

And AngularJS version : 1.6.8

Upvotes: 6

Views: 3942

Answers (2)

dapperdandev
dapperdandev

Reputation: 3298

For anyone struggling with this is 2024, here are two options

Basic AngularJS service injection inside of modern Angular

export class MyComponent {
    private readonly upgrade = inject(UpgradeModule);
    private readonly authService = this.upgrade.$injector.get("authService");
}

Using an AngularJS service inside of APP_INITIALIZER

import * as angular from 'angular'; // import AngularJS

export const appConfig: ApplicationConfig = {
    providers: [
        {
            provide: AuthService,
            useFactory: () => {
                const injector = angular.injector(["ng", "auth.module"]); // Replace "auth.module" with the name of the AngularJS module the service belongs to.  
                return injector.get("authService");
            }
        },
        {
            provide: APP_INITIALIZER,
            useFactory: (authService: AuthService) => (): void => {
                // use authService
            },
            deps: [AuthService],
            multi: true
        }
    ]
};

Upvotes: 0

Gopherkhan
Gopherkhan

Reputation: 4342

This means you are pulling in an AngularJS dependency somewhere in your component tree. It may be in your immediate component or some dependency further down the line.

To debug:

Method 1

Add a debugger statement immediately before your bootstrap call:

it('should render the component', () => {
   debugger;
   bootstrap(Ng2AppComponent);
   ...
 });
  1. With your JS Console open, let the test run and pause at the debugger location.
  2. Click the Stop/Pause icon (in the sidebar on the 'sources' tab) and checkmark "Pause on Exceptions". Unpause the debugger.
  3. The debugger should stop within a call to injectorFactory. Use the stack explorer to find calls to resolveNgModuleDep. These will be recursive, so the top of the stack will be closer to a leaf node, while calls further down the stack will be closer to your component being tested. Look for lines like: tokenKey = "ServiceName". This is potentially your offending service.
  4. Dive down the stack one more layer to find which component tried to inject that service.
  5. Within your test, mock out a provider to handle that specific injection. Note that this code assumes only one problem injection. For multiple injector issues, you will need to special case these:
 beforeEach(() => {
   setupModule({
     imports: [
       ...
     ],
     providers: [
       {
         provide: '$injector',
         useValue: {
           get: () => {
             return new MockService();  // enhance as needed
           },
         }
       }
     ],
   });

Method 2

  1. Mock out a provider for the $injector call, and return an empty object.
beforeEach(() => {
   setupModule({
     imports: [
       ...
     ],
     providers: [
       {
         provide: '$injector',
         useValue: {
           get: (serviceName?: string) => {
            console.log('looking for serviceName:', serviceName);
            return {};  // this will break things differently
           },
         }
       }
     ],
   });
  1. Look at your console output to find the offending service / signature. This may or may not involve less work than than Method 1.

Upvotes: 4

Related Questions