【问题标题】:Error when using AngularJS component inside Angular app: "Error: Trying to get the AngularJS injector before it being set."在 Angular 应用程序中使用 AngularJS 组件时出错:“错误:尝试在设置 AngularJS 注入器之前获取它。”
【发布时间】:2018-09-11 20:55:32
【问题描述】:

我正在通过 Angular 的 upgrade guide 学习如何在 Angular 应用程序中嵌入 AngularJS 组件。我使用 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时每个文件的import语句都不一样?您似乎也没有对第一个文件中导入的 MyComponent 执行任何操作。
  • @Pop-A-Stash - 我稍微简化了示例,但我更新了我的问题以说明我为什么导入组件;这样我就可以引用组件的选择器字符串,该字符串存储为组件类的属性。这两个文件从 @my-company/module-test 导入不同的东西,因为模块导出了多个命名导出。
  • 我在 Angular 的 GitHub 上打开了一个问题:github.com/angular/angular/issues/23141
  • 我有同样的问题stackblitz.com/edit/angular-pyvy53
  • 当我在多个 NgModule 中导入 UpgradeModule 时出现此错误。一旦我删除它,它就消失了。

标签: javascript angularjs angular typescript angular-upgrade


【解决方案1】:

我遇到了同样的问题,终于解决了。在引导混合 Angular/angularjs 应用程序之前,需要遵循一些步骤。

  1. 安装升级模块npm install @angular/upgrade

  2. 将您的“CompanyModule”(注册所有公司组件的模块)包装到一个新的 angularjs 模块中(例如:Ng1Shared)。如果您的公司组件没有模块,则必须创建它。比降级 AppComponent 如下所示。

    const MyCompanyModule = angular
       .module('MyCompanyModule', [])
       .component('myComponent', MyComponent)
       .name;
    
    
    const Ng1Shared = angular
       .module('Ng1Shared', [MyCompanyModule])
       .directive('appRoot', downgradeComponent({ component: AppComponent }))
       .name; 
    
  3. 使用基本导入(BrowserModule、CommonModule、UpgradeModule)配置 AppModule。将 angularjs 的注入器提供给 Angular;声明一个“entryComponent”并删除 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. 使用 UpgradeModule 本身提供的函数全局设置 angularjs,并使用 @angular/core 提供的 DoBootstrap 方法手动引导 Angular。

    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. 为每个 angularjs 组件创建一个包装器指令,并将其添加到 AppModule 的声明数组中。

    @Directive({
        selector: 'my-component'
    })
    export class MyComponentWrapper extends UpgradeComponent {
        @Input() title: string;
    
        constructor(elementRef: ElementRef, injector: Injector) {
          super('myComponent', elementRef, injector);
        }
    }
    

我写了一个简单的example available on stackblitz。 例如,我将 angularjs MyCompanyModule 添加到另一个名为 Ng1Module 的 angularjs 模块中。如您所见,angularjs 和 angular 组件之间的属性绑定也可以正常工作。

希望对你有用。

【讨论】:

    【解决方案2】:

    https://github.com/angular/angular/issues/23141#issuecomment-379493753

    您不能直接引导包含以下内容的 Angular 组件 在引导 AngularJS 之前升级组件。相反,您可以 降级 AppComponent 并让它作为 AngularJS 应用程序的一部分:

    https://stackblitz.com/edit/angular-djb5bu?file=app%2Fapp.module.ts

    【讨论】:

      【解决方案3】:

      尝试像这样将 entryComponents 添加到您的 AppModule 中:

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

      【讨论】:

        猜你喜欢
        • 2019-06-09
        • 2019-01-30
        • 1970-01-01
        • 2019-07-15
        • 2020-10-04
        • 2017-12-12
        • 2020-07-21
        • 1970-01-01
        • 2018-05-13
        相关资源
        最近更新 更多