I searched a lot of posts and also the official Angular documentation, but I'm not able to get an AngularJS service running in Angular. I finally came to this page https://angular.io/api/upgrade/static/UpgradeModule#examples which seems to explain exactly what I need, but when doing all those steps I'm getting:
ERROR Error: Trying to get the AngularJS injector before it being set.
My impression is that this example is not quite complete. E.g. there is no hint were the (old) AngularJS framework must be loaded. My service looks like angular.module('my-module').service('my-service', ...
thus angular
needs to be defined, otherwise I'm getting an error. Furthermore many examples assume that the AngularJS code is written in TypeScript. In my case this is not true (just plain Javascript).
Unfortunately with Angular 9 there is an additional issue with the @angular/upgrade
module which is not mentioned anywhere and can only be solved by disabling the new Ivy compiler in tsconfig.app.json
, otherwise the compiler will throw Error: Error on worker #1: Error: getInternalNameOfClass() called on a non-ES5 class: expected UpgradeComponent to have an inner class declaration
:
"angularCompilerOptions": {
"enableIvy": false
}
I'd really appreciate if somebody could post a complete example on what exactly must be done in order to run an AngularJS service in an Angular component.
UPDATE [6th July 2020]
Here you can find a GitHub repo which you can clone, to reproduce the behavior: https://github.com/berkon/angularjs-service-upgrade-test. I should also mention that I'm using the Electron framework and started based on this repo https://github.com/maximegris/angular-electron but I guess that shouldn't matter in this case.
Finally I got it working! It was really really cumbersome to figure this all out. A lot of things aren't mentioned in most tutorials and even in the official Angular guide there are only code snippets which make it hard for Angular newbies to guess where to put all that stuff. Also the bootstraping is not explained correctly. Furthermore all tutorials assume that the "old" AngularJS code is already written in TypeScript, which makes it even harder to find the right way/order to load/bootstrap/import all that stuff. Finally there seems to be an issue with the @angular/upgrade module in combination with the new Ivy compiler in Angular 9. It throws the error mentioned below. Thus it must be disabled to get things working. A real pain!!!
So roughly these are the steps:
angular
and @angular/upgrade
node modules.js
modules including AngularJS in the script
section of angular.json
bootstrap
section from @NgModule and bootstrap AngularJS via ngDoBootstrap
manually. First bootstrap
AngularJS, afterwards bootstrap the AppComponent class. This way the service is available at AppComponent initialization. Otherwise you'll get an injection error!providers []
section to get access to the new serviceIts quite a lot of work to perform all steps below manually, but I listed them for reference. Here you can find a GitHub repo where you can clone a working app. Don't be surprised! This repo uses the Electron framework (electronjs.org). But don't worry this doesn't have any influence on my findings: https://github.com/berkon/angularjs-service-upgrade-test
And here is the step-by-step guide:
Prerequistes
execute npm install angular --save
execute npm install @angular/upgrade --save
in tsconfig.app.json
add "enableIvy": false
to angularCompilerOptions
to avoid getting:
Error: getInternalNameOfClass() called on a non-ES5 class: expected UpgradeComponent to have an inner class declaration
add "node_modules/angular/angular.js"
and the Javascript file which contains your AngularJS service (in this case "src/app/angular-js-service.js"
) to the scripts []
array in angular.json
app.module.ts
add ApplicationRef
to the import brackets of @angular/core
add import { UpgradeModule } from '@angular/upgrade/static'
add UpgradeModule
to imports []
array of @NgModule
remove bootstrap
section completely from @NgModule
and replace it with this: entryComponents: [AppComponent]
add this to the providers []
array in @NgModule
and make sure to replace myService
with the correct name of your service:
{ provide: 'myService', useFactory: (i: any) => { return i.get('myService') }, deps: ['$injector'] }
replace the constructor of AppModule
with this:
constructor ( public upgradeModule: UpgradeModule ) {}
add this to the AppModule
class and make sure to replace ajsAppModule
with the name of your AngularJS main app module:
ngDoBootstrap ( appRef: ApplicationRef ) {
this.upgradeModule.bootstrap(document.body, ['ajsAppModule'], { strictDi: true } )
appRef.bootstrap ( AppComponent )
}
app.component.ts
add Inject
to the import brackets at @angular/core
in the AppComponent
class change the constructor to this and make sure to replace myService
with the name of your AngularJS service
constructor ( @Inject('myService') myService: any ) {
myService.doSomething()
}