无法使 AngularJS 服务在 Angular 中工作

Unable to get AngularJS service working in Angular

我搜索了很多 posts 和官方 Angular 文档,但我无法获得 AngularJS 服务 运行ning Angular。我终于来到了这个页面 https://angular.io/api/upgrade/static/UpgradeModule#examples,它似乎准确地解释了我需要什么,但是在执行所有这些步骤时我得到:

ERROR 错误:在设置 AngularJS 注入器之前尝试获取它。

我的印象是这个例子不是很完整。例如。没有提示必须加载(旧的)AngularJS 框架。我的服务看起来像 angular.module('my-module').service('my-service', ...,因此需要定义 angular,否则我会收到错误消息。此外,许多示例假设 AngularJS 代码是用 TypeScript 编写的。在我的例子中,这不是真的(只是简单的 Javascript)。

不幸的是 Angular 9 @angular/upgrade 模块还有一个额外的问题,这个问题在任何地方都没有提到,只能通过在 tsconfig.app.json 中禁用新的 Ivy 编译器来解决,否则编译器会抛出 Error: Error on worker #1: Error: getInternalNameOfClass() called on a non-ES5 class: expected UpgradeComponent to have an inner class declaration:

"angularCompilerOptions": {
    "enableIvy": false
}

如果有人能 post 一个完整的例子,说明为了 运行 AngularJS 服务在 Angular 中必须做什么,我将不胜感激组件。

更新 [2020 年 7 月 6 日]

在这里您可以找到一个 GitHub 存储库,您可以克隆它来重现该行为: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 但我想这在这种情况下应该无关紧要。

我有同样的错误,我在我的应用程序中解决了它,但是我不记得为什么会发生这种情况(抱歉,那是很久以前的事了)。我不是在升级服务,而是在降级。

这是我的 app.module.ts 我已经在对实现此功能至关重要的部分添加了评论,我希望这里可能对您有所提示。请注意,我使用 Angular CLI 生成应用程序。

setAngularJSGlobal(angular);

// Configure the angularjs app (yours might be defined elsewhere)
const app = angular.module('app', [MyFormsModule, AngularMaterialModule]);

app.run(RunAddressAutocompleteConfig);
app.run(RunDynamicQueryConfig);

// Downgrade Angular AppComponent so AngularJS can render it after bootstrapping
// my app used an Angular component as the root
app.directive('appRoot', downgradeComponent({ component: AppComponent }));

// Downgrade Angular services
app.factory('api', downgradeInjectable(ApiService));
app.factory('dynamicQuery', downgradeInjectable(DynamicQueryService));

@NgModule({
  declarations: [
    AppComponent,
    FormDirective,
    FormPageComponent,
    FormsListPageComponent,
    RouterLinkPreserveQueryParamsDirective,
    FormEmptyStatePageComponent,
  ],
  imports: [BrowserModule, UpgradeModule, AppRoutingModule, HttpClientModule, CommonModule],
  // This was absolutely necessary for bootstrapping my app in this way
  // I encountered errors otherwise
  providers: [
    {
      provide: '$scope',
      useExisting: '$rootScope',
    },
  ],
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
  entryComponents: [AppComponent],
})
export class AppModule implements DoBootstrap {
  constructor(private readonly upgrade: UpgradeModule) {}

  ngDoBootstrap(appRef: ApplicationRef) {
    this.upgrade.bootstrap(document.body, [app.name], { strictDi: true });
    appRef.bootstrap(AppComponent);
  }
}

index.html

<body>
    <app-root></app-root>
</body>

我终于成功了!弄清楚这一切真的很麻烦。大多数教程中都没有提到很多东西,甚至在官方 Angular 指南中也只有代码片段,这让 Angular 新手很难猜出把所有这些东西放在哪里。 bootstraping 也没有正确解释。此外,所有教程都假设“旧的”AngularJS 代码已经用 TypeScript 编写,这使得找到正确的 way/order 到 load/bootstrap/import 所有这些东西变得更加困难。最后,@angular/upgrade 模块与 Angular 9 中新的 Ivy 编译器的组合似乎存在问题。它抛出下面提到的错误。因此必须禁用它才能正常工作。真的很痛苦!!!

大致是这些步骤:

  • 安装 angular@angular/upgrade 节点模块
  • 加载所有 .js 模块,包括 AngularJS 在 angular.json
  • script 部分
  • 通过手动从@NgModule 和bootstrap AngularJS 中删除bootstrap 部分,通过ngDoBootstrap 中断常规Angular bootstrap 进程.首先 bootstrap AngularJS,之后bootstrap AppComponent class。这样,该服务在 AppComponent 初始化时可用。否则会出现注入错误!
  • providers [] 部分添加新提供商以访问新服务
  • 现在可以在 AppComponent 的构造函数中注入新的(升级的)服务

手动执行以下所有步骤的工作量相当大,但我列出它们以供参考。在这里您可以找到一个 GitHub 存储库,您可以在其中克隆一个可用的应用程序。不要惊讶!这个 repo 使用 Electron 框架 (electronjs.org)。不过请放心,这对我的发现没有任何影响:https://github.com/berkon/angularjs-service-upgrade-test

这里是分步指南:

先决条件

  • 执行npm install angular --save

  • 执行npm install @angular/upgrade --save

  • tsconfig.app.json 中添加 "enableIvy": falseangularCompilerOptions 以避免得到:

    Error: getInternalNameOfClass() called on a non-ES5 class: expected UpgradeComponent to have an inner class declaration
    
  • "node_modules/angular/angular.js" 和包含您的 AngularJS 服务(在本例中为 "src/app/angular-js-service.js")的 Javascript 文件添加到 scripts []数组在angular.json

app.module.ts

  • ApplicationRef添加到@angular/core

    的导入括号中
  • 添加import { UpgradeModule } from '@angular/upgrade/static'

  • UpgradeModule 添加到 @NgModule

    imports [] 数组
  • @NgModule 中完全删除 bootstrap 部分并将其替换为:entryComponents: [AppComponent]

  • 将其添加到 @NgModule 中的 providers [] 数组,并确保将 myService 替换为您的服务的正确名称:

    { provide: 'myService', useFactory: (i: any) => { return i.get('myService') }, deps: ['$injector'] }
    
  • AppModule的构造函数替换为:

    constructor ( public upgradeModule: UpgradeModule ) {}
    
  • 将其添加到 AppModule class 并确保将 ajsAppModule 替换为您的 AngularJS 主应用程序模块的名称:

    ngDoBootstrap ( appRef: ApplicationRef ) {
        this.upgradeModule.bootstrap(document.body, ['ajsAppModule'], { strictDi: true } )
        appRef.bootstrap ( AppComponent )
    }
    

app.component.ts

  • Inject 添加到 @angular/core

    处的导入括号中
  • AppComponent class 中将构造函数更改为此,并确保将 myService 替换为您的 AngularJS 服务的名称

    constructor ( @Inject('myService') myService: any ) {
        myService.doSomething()
    }