在 Angular 组件中使用 AngularJS 指令

13
我正在尝试升级一个AngularJS指令以在我的Angular组件中使用。我已经使混合(ng1 + ng2)环境正常工作。我还可以在Angular中注入AngularJS服务并在Angular组件中使用它们(实际上,我甚至让它与AngularJS 1.4.x一起工作)。现在,我正在尝试在Angular中使用一个现有的AngularJS指令,但是不起作用。以下是我的一些代码片段供参考。【index.html】(my-app是Angular 4根组件)
...
<body>
    <div class="banner">Angular Migration</div>
    <my-app>Loading...</my-app>
...
</body>
...

[main.ts](引导代码)

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { UpgradeModule } from '@angular/upgrade/static';
import { Router } from '@angular/router';
import { AppModule } from './app.module';

platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => {
  let upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule;
  upgrade.bootstrap(document.documentElement, ['sampleApp']);
  platformRef.injector.get(Router).initialNavigation();
});

[app.module.ts] (Angular 4 模块)

import { NgModule, Component } from '@angular/core';
import { HashLocationStrategy, LocationStrategy, CommonModule } from '@angular/common';
import { BrowserModule } from '@angular/platform-browser';
import { UpgradeModule } from '@angular/upgrade/static';
import { RouterModule, Routes, UrlHandlingStrategy } from '@angular/router';

import { HybridUrlHandlingStrategy } from './hybridUrlHandlingStrategy';
import { AppComponent } from './app.component';

export const routes: Routes = [
...
];

@NgModule({
  imports: [
    CommonModule,
    BrowserModule,
    UpgradeModule,
    RouterModule.forRoot([], { useHash: true, initialNavigation: false })
  ],
  providers: [
    { provide: LocationStrategy, useClass: HashLocationStrategy },
    { provide: UrlHandlingStrategy, useClass: HybridUrlHandlingStrategy },
    { provide: 'appService', useFactory: (i: any) => i.get('appService'), deps: ['$injector'] },
    { provide: 'mdToHtml', useFactory: (i: any) => i.get('mdToHtml'), deps: ['$injector'] }
  ],
  declarations: [
    AppComponent
  ],
  bootstrap: [ AppComponent ]    
})
export class AppModule {
  ngDoBootstrap() { }
}

[app.component.ts] (Angular 4组件)

import { Component } from '@angular/core';

@Component({
  selector: 'my-app',
  template: `
    <router-outlet></router-outlet>
    <div ng-view></div>
  `,
})
export class AppComponent { }

[app.js](AngularJs应用程序)

'use strict';

angular.module('sampleApp', [
  'ngRoute',
  'app.components.services.appService'
])
  .config(function ($routeProvider) {
    $routeProvider
      .otherwise({
        template: ''
      });
  });

[myStars.js](AngularJs指令)

'use strict';

angular.module('app.components.directives.myStars', [])
.controller('MyStarsCtrl', function() {
  console.log("**** in MyStarsCtrl ")
})
.component('myStars', {
  restrict: 'E',
  bindings: {
    count: '=count'
  },
  template: '<div>***** M Y   S T A R S *****</div>'
});

[myStars.ts](尝试将myStars指令迁移到Angular 4)
import { Directive, ElementRef, Injector, Input, Output, EventEmitter } from '@angular/core';
import { UpgradeComponent } from '@angular/upgrade/static';

@Directive({
  selector: 'my-stars'
})
export class MyStarsDirective extends UpgradeComponent {
  @Input() count: number;
  @Output() clicked: EventEmitter<number>;

  constructor(elementRef: ElementRef, injector: Injector) {
    super('myStars', elementRef, injector);
  }
}

[test.module.ts] (Angular 4测试模块)

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule, Routes} from '@angular/router';
import { TestComponent } from './test.component';

// importing the new MyStarsDirective)
import { MyStarsDirective } from '../../../components/directives/myStars/myStars';

const thisRoute: Routes = [
    {
        path: 'test/:id',
        component: TestComponent
    }
];

@NgModule({
    declarations: [
        TestComponent,
        MyStarsDirective, // <<<< adding directive here
    ],
    providers: [],
    imports: [
        CommonModule,
        RouterModule.forChild(thisRoute)
    ],
    exports: [
        RouterModule
    ]
})

export class TestModule {}

[test.component.ts] (Angular 4测试组件)

import { Component, Inject, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { FormsModule } from '@angular/forms';
import { HybridUrlHandlingStrategy } from '../../../hybridUrlHandlingStrategy';
import { MyStarsDirective } from '../../../components/directives/myStars/myStars';

@Component({
  templateUrl: './test.component.html'
})
export class TestComponent implements OnInit {
  routeParams: any
  myService: any
  mdToHtml: any

  constructor(
    @Inject('myService') myService: any,
    @Inject('mdToHtml') mdToHtml: (str: string) => string,
    private activatedRoute: ActivatedRoute
  ) {
    this.myService = myService;
    this.mdToHtml = mdToHtml;
  }
  ngOnInit() {
    this.routeParams = this.activatedRoute.params.subscribe(params => {
      console.log("params", params['groupId'])
...
  }
  ngOnDestroy() {
    this.routeParams.unsubscribe();
  }
}

[test.component.html] (Angular 4 html)

...
<my-stars></my-stars>      <!-- <<<< using directive here -->
...

注意:我已经将AngularJS版本升级到1.5,只是为了使这个混合应用程序能够运行。 以下是当我浏览测试组件页面时出现的错误:

enter image description here

任何帮助都将不胜感激。
谢谢。

2
你的代码中在哪里使用了 $scope? - Bruno Poeta
@BrunoPoeta,我在AngularJS代码中有$scope,但在升级后的组件中没有找到。 - Will
很奇怪,因为zone.js抛出的错误说你在组件的某个地方有它。 - Bruno Poeta
@BrunoPoeta 有人说可能是我引导这两个框架的方式。 - Will
@BrunoPoeta 顺便说一下,我的其他AngularJS指令和控制器中确实有$scope。我还没有尝试迁移或升级它们。这会有影响吗? - Will
@BrunoPoeta 搞定了。你的问题让我真正关注了 $scope,最终在这个链接中找到了答案:https://github.com/angular/angular/issues/14993。请看 gkalpak 在 3 月 10 日的评论。 - Will
1个回答

13

如果有人感兴趣的话,这里是解决此错误的方法。

[test.module.ts] (Angular 4测试模块)

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule, Routes} from '@angular/router';
import { TestComponent } from './test.component';

// importing the new MyStarsDirective)
import { MyStarsDirective } from '../../../components/directives/myStars/myStars';

const thisRoute: Routes = [
    {
        path: 'test/:id',
        component: TestComponent
    }
];

@NgModule({
    declarations: [
        TestComponent,
        MyStarsDirective, // <<<< adding directive here
    ],
    providers: [
        {
            provide: '$scope',
            useFactory: i => i.get('$rootScope'),
            deps: ['$injector']
        }, // <<<< added this section to fix the No provider for $scope error
    ],
    imports: [
        CommonModule,
        RouterModule.forChild(thisRoute)
    ],
    exports: [
        RouterModule
    ]
})

export class TestModule {}
我在这个链接中找到了答案:https://github.com/angular/angular/issues/14993 (灵感来自BrunoPoeta) 请参考gkalpak于3月10日的评论。
现在让我们看看是否可以升级一个普通指令并使用1.4.x版本。

太好了!我很高兴能帮助你,威尔! - Bruno Poeta
节省了我大量的时间,谢谢。在找到这个答案之前,我花了几天时间试图解决问题。 - Nicolas Gehlert

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