在Angular应用程序中使用AngularJS组件时出错:“Error: Trying to get the AngularJS injector before it being set.”

8
我正在学习如何在Angular应用程序中嵌入AngularJS组件,因此正在阅读Angular的升级指南。 我使用Angular CLI创建了一个简单的Angular应用程序,并添加了一个简单的AngularJS模块作为依赖项。
当我运行ng serve时,应用程序成功编译且没有错误。 但是,在运行时,我在控制台上收到以下消息:
Error: Trying to get the AngularJS injector before it being set.

什么原因导致了这个错误,我该如何避免它?我没有偏离升级指南中详细说明的步骤。
以下是我在Angular应用程序中升级AngularJS组件的方式:
// 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);
    }
}

这是我的 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
        });
    }
}

我正在使用Angular 5.2.0。


当引用@my-company/module-test时,为什么每个文件的导入语句都不同?而且在第一个文件中似乎没有对导入的MyComponent进行任何操作。 - Pop-A-Stash
@Pop-A-Stash - 我简化了示例,但我已更新我的问题以显示为什么导入组件; 这是为了可以引用组件类上存储的组件选择器字符串属性。这两个文件从 @my-company/module-test 导入不同的内容,因为该模块导出多个命名导出。 - Nathan Friend
1
我在Angular的GitHub上开了一个问题,链接在这里:https://github.com/angular/angular/issues/23141 - Nathan Friend
1
我有同样的问题。 https://stackblitz.com/edit/angular-pyvy53 - Amin Rahimi
当我在多个 NgModule 中导入 UpgradeModule 时,我遇到了这个错误。一旦我将其移除,错误就消失了。 - Carlo Bos
@Amin Rahimi:你需要在 Stackblitz 的 HTML 中添加<head>和<body>标签,并将脚本引用(jquery&angular)放置在<head>部分。 - Kieran Ryan
3个回答

9

我遇到了同样的问题,并最终解决了它。在启动混合Angular / AngularJS应用之前,需要遵循一些步骤。

  1. Install the UpgradeModule npm install @angular/upgrade

  2. 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; 
    
  3. 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
    })
    
  4. 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);
      }
    }
    
  5. 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);
        }
    }
    

我在 stackblitz 上编写了一个简单的示例。

为了演示,我将angularjs的MyCompanyModule添加到另一个angularjs模块中,称为Ng1Module。如您所见,angularjs和angular组件之间的属性绑定也可以正常工作。

希望这对你有用。


0

0
尝试像这样向您的AppModule添加entryComponents:

...
@NgModule({
    declarations: [AppComponent, ExampleDirective],
    imports: [BrowserModule, AppRoutingModule, UpgradeModule],
    entryComponents: [
          AppComponent // Don't forget this!!!
    ],
    providers: [],
    // bootstrap: [AppComponent] // Delete or comment this line 
})
...

使用Ivy引擎,这不再需要。https://angular.io/guide/deprecations#entrycomponents-and-analyze_for_entry_components-no-longer-required - cloakedninjas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接