2

I'm searching for include AngularJS service inside Angular project.

This is my main.ts:

import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
import {AppModule} from './app/app.module';
import {UpgradeModule} from "@angular/upgrade/static";
import {environment} from './environments/environment';

platformBrowserDynamic().bootstrapModule(AppModule)
  .then(ref => {
    const upgrade = ref.injector.get(UpgradeModule) as UpgradeModule;
    upgrade.bootstrap(document.body, ['dmdWorkplace', 'dmdLogin'], {strictDi: true});
  })
  .catch(err => console.log(err));

And this is my app.module.ts:

//@angular
import {BrowserModule} from '@angular/platform-browser';
import {CUSTOM_ELEMENTS_SCHEMA, Inject, NgModule} from '@angular/core';
import {UpgradeModule} from '@angular/upgrade/static';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {HttpClientModule} from '@angular/common/http';

//Modules
import {AppRoutingModule} from './app-routing.module';
import {MaterialModule} from './material.module';

//Components
import {DmdWhlComponentMain} from './main/dmd-whl.component.main';
import {DmdWhlComponentRegistries} from './registries/dmd-whl.component.registries';

//Services
import {DmdWhlGlobalService} from './services/dmd-whl.global.service';
import {DmdWhlLabelService} from './services/dmd-whl.label.service';

import {TranslateModule, TranslateService} from '@ngx-translate/core';
import {DOCUMENT} from "@angular/common";

@NgModule({
  declarations: [
    DmdWhlComponentMain,
    DmdWhlComponentRegistries
  ],
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    MaterialModule,
    AppRoutingModule,
    UpgradeModule,
    HttpClientModule,
    TranslateModule.forRoot()
  ],
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
  entryComponents: [DmdWhlComponentMain],
  providers: [
    DmdWhlGlobalService,
    DmdWhlLabelService,
    {
      provide: 'dmdLoginAuthenticationService',
      useFactory: (i) => {
        i.get('dmdLoginAuthenticationService')
      },
      deps: ['$injector']
    },
    {
      provide: '$scope',
      useFactory: i => i.get('$rootScope'),
      deps: ['$injector']
    }
  ],
  bootstrap: [DmdWhlComponentMain]
})

export class AppModule {
  labels: object = {};
  browserLanguage = navigator.language === 'en' ? 'en-US' : 'it-IT';

  constructor(private labelService: DmdWhlLabelService,
              private translate: TranslateService,
              @Inject('dmdLoginAuthenticationService') dmdLoginAuthenticationService,
              @Inject(DOCUMENT) private document: Document) {
    this.getLabels();
    this.run();
  }

  ngDoBootstrap() {
  }

  getLabels() {
    this.labelService.getLabels(this.browserLanguage, 'label').then(res => {
      this.translate.setDefaultLang('it'); //Sets the default language to use as a fallback
      this.translate.setTranslation(navigator.language, res['data'][this.browserLanguage]); //Sets an object of translations for a given language
    });
  }

  run() {
    if (navigator.platform.match('Mac') !== null) {
      this.document.body.classList.add('mac');
    }
  }
}

The error is:

Error: Trying to get the AngularJS injector before it being set.
    at injectorFactory (static.js:678)
    at _callFactory (core.js:10645)
    at _createProviderInstance$1 (core.js:10599)
    at initNgModule (core.js:10549)
    at new NgModuleRef_ (core.js:11792)
    at createNgModuleRef (core.js:11782)
    at Object.debugCreateNgModuleRef [as createNgModuleRef] (core.js:14092)
    at NgModuleFactory_.create (core.js:15216)
    at eval (core.js:5370)
    at ZoneDelegate.invoke (zone.js:392)
Kim Kern
  • 54,283
  • 17
  • 197
  • 195
Mauro Bove
  • 31
  • 2

1 Answers1

2

I had the same error message today and could solve it. It looks like your code is suffering from the same problem.

In a hybrid app you always need to bootstrap AngularJS first. To accomplish this, remove the upgrade part (the whole call to then(...)) in main.ts, change

  bootstrap: [DmdWhlComponentMain]

into

  entryComponents: [DmdWhlComponentMain]

in your AppModule, and implement ngDoBootstrap() this way:

  ngDoBootstrap(app) {
    this.upgrade.bootstrap(document.body, ['dmdWorkplace', 'dmdLogin'], {strictDi: true});
    app.bootstrap(DmdWhlComponentMain);
  }

Credits go to https://blog.angularindepth.com/how-to-manually-bootstrap-an-angular-application-9a36ccf86429 which helped me solve this problem.

Matthias
  • 1,759
  • 16
  • 34
  • For you both I can add that the UpgradeModule has a performance problem in that it causes an explosion of digest cycles (see chrome debugger) Angular 5 solves that by introducing the downgradeModule(). Performance is much better but then you cannot reference a downgraded injector outside downgraded components or you will get this error as well. Reason is that the factories gets initialized async when called which the angular components cannot handle. My solution was to create a ServiceBootstrapper component and inject all downgraded injectables and then instanciate that as entry component. – JGoodgive Jan 18 '18 at 19:04
  • Solved a problem in a hybrid app where we couldn’t use the angularjs services in an angular app. This still seems very relevant. Thank you very much – ArchiFloyd Aug 12 '19 at 13:22