I'm working through Angular's upgrade guide to learn how to embed AngularJS components in an Angular app. I've created a bare-bones Angular app using the Angular CLI and added a simple AngularJS module as a dependency.
When I run ng serve
, the application compiles with no errors. However, at runtime, I get this message in the console:
Error: Trying to get the AngularJS injector before it being set.
What is causing this error, and how can I avoid it? I haven't deviated from the steps detailed in the upgrade guide.
Here's how I'm upgrading my AngularJS component inside my Angular app:
// example.directive.ts
import { Directive, ElementRef, Injector } from '@angular/core';
import { UpgradeComponent } from '@angular/upgrade/static';
// this is the npm module that contains the AngularJS component
import { MyComponent } from '@my-company/module-test';
@Directive({
selector: 'my-upgraded-component'
})
export class ExampleDirective extends UpgradeComponent {
constructor(elementRef: ElementRef, injector: Injector) {
// the .injectionName property is the component's selector
// string; "my-component" in this case.
super(MyComponent.injectionName, elementRef, injector);
}
}
And here's my app.module.ts
:
// app.module.ts
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { UpgradeModule } from '@angular/upgrade/static';
import { ExampleDirective } from './example.directive';
import { myModuleName } from '@my-company/module-test';
@NgModule({
declarations: [AppComponent, ExampleDirective],
imports: [BrowserModule, AppRoutingModule, UpgradeModule],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {
constructor(private upgrade: UpgradeModule) {}
ngDoBootstrap() {
this.upgrade.bootstrap(document.body, [myModuleName], {
strictDi: true
});
}
}
I'm using Angular 5.2.0.
I faced the same issue, and finally solved it. There are some steps to follow before bootstrap an hybrid Angular/angularjs application.
Install the UpgradeModule npm install @angular/upgrade
Wrap your "CompanyModule" (the module where all your company components are registered) into a new angularjs module (for instance: Ng1Shared). If you not have a module for your company components, it must be created. Than downgrade AppComponent as shown below.
const MyCompanyModule = angular
.module('MyCompanyModule', [])
.component('myComponent', MyComponent)
.name;
const Ng1Shared = angular
.module('Ng1Shared', [MyCompanyModule])
.directive('appRoot', downgradeComponent({ component: AppComponent }))
.name;
Configure AppModule with basic imports (BrowserModule, CommonModule, UpgradeModule). Provide the angularjs' Injector to Angular; declare an "entryComponent" and remove the default bootstrap for AppComponent.
@NgModule({
imports: [BrowserModule, CommonModule, UpgradeModule],
declarations: [AppComponent],
providers: [{provide: '$scope', useExisting: '$rootScope'}], // REQUIRED
entryComponents: [AppComponent], // ADD AN ENTRY COMPONENT
// bootstrap: [AppComponent] MUST BE REMOVED
})
Set angularjs globally with a function provided by UpgradeModule itself and manually bootstrap Angular with DoBootstrap method provided by @angular/core.
export class AppModule implements DoBootstrap {
constructor(private upgrade: UpgradeModule) { }
public ngDoBootstrap(app: any): void {
setAngularJSGlobal(angular);
this.upgrade.bootstrap(document.body, [Ng1Shared], { strictDi: false });
app.bootstrap(AppComponent);
}
}
Create a wrapper directive for every angularjs component and add it to AppModule's declaration array.
@Directive({
selector: 'my-component'
})
export class MyComponentWrapper extends UpgradeComponent {
@Input() title: string;
constructor(elementRef: ElementRef, injector: Injector) {
super('myComponent', elementRef, injector);
}
}
I wrote a simple example available on stackblitz. For example purposes I added angularjs MyCompanyModule to another angularjs module, called Ng1Module. As you can see also property binding between angularjs and angular component works fine.
I hope it can be useful.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With