angular 5.0の場合、アップグレードモジュールには、angularゾーンの外でangularjsを実行するdowngradeModuleを使用するオプションがあります。これを試してみると問題が発生しましたdowngradeInjectableを使用します。
エラーが表示されます:
キャッチされないエラー:Angularモジュールをブートストラップする前にAngularインジェクタを取得しようとしています。
Bootstrapping angular in angular jsは正常に動作します
import 'zone.js/dist/zone.js';
import * as angular from 'angular';
/**
* Angular bootstrapping
*/
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { decorateModuleRef } from 'src/environment';
import { AppModule } from 'src/app/app.module';
import { downgradeModule } from '@angular/upgrade/static';
export const bootstrapFn = ( extraProviders ) => {
const platformRef = platformBrowserDynamic( extraProviders );
return platformRef
.bootstrapModule( AppModule )
.then( decorateModuleRef );
};
angular.module( 'app.bootstrap', [
downgradeModule( bootstrapFn ),
] );
ただし...
Angularjsが初期化された後にブートストラップが行われるため、ダウングレードインジェクタブルを機能させることができなくなります。
ダウングレードするサービス
import { Injectable, Inject, OnInit } from '@angular/core';
@Injectable()
export class MobileService implements OnInit{
constructor(
@Inject( 'angularjsDependency1' ) public angularjsDependency1 : any,
@Inject( 'angularjsDependency2' ) public angularjsDependency2 : any,
) {}
}
注射可能なダウングレードの試み
import * as angular from 'angular';
import { downgradeInjectable } from '@angular/upgrade/static';
import { MyService } from 'src/services/myService/myService';
export const myServiceDowngraded = angular.module( 'services.mobileService', [
angularjsDependency1,
angularjsDependency2,
] )
.factory(
'mobileService',
downgradeInjectable( MyService ),
).name;
「downgradeInjectable(MyService)を実行すると、angularがまだ起動されていないため、angularインジェクタはまだ使用できません。したがって、エラー:
キャッチされないエラー:Angularモジュールをブートストラップする前にAngularインジェクタを取得しようとしています。
誰かが私がこれをどのように修正するか考えていますか?
注:以下の回答は、angular 1.xをangularjsとして呼び出し、すべてのangular 2+バージョンを単にangularとして呼び出します。 =
上記のJGoodgiveの答えを拡張すると、基本的に、downgradeModule
を使用している場合、angularモジュールは、最初のangularコンポーネント。それまでは、angularモジュールが初期化されていないため、downgradeInjectable
、それらのサービスも利用できません。
回避策は、angularモジュールのブートストラップをできるだけ早く強制することです。これには、単純なコンポーネントが必要です:
import {Component} from '@angular/core';
@Component({
selector: 'service-bootstrap'
template: ''
})
export class ServiceBootstrapComponent {}
このコンポーネントは何もしません。次に、このコンポーネントをトップレベルで宣言しますangularモジュール。
@NgModule({
// ...providers, imports etc.
declarations: [
// ... existing declarations
ServiceBootstrapComponent
],
entryComponents: [
// ... existing entry components
ServiceBootstrapComponent
]
})
export class MyAngularModule {}
次に、このコンポーネントのダウングレードしたバージョンをangularjsモジュールに追加する必要もあります。 (私はこれを私が持っていたトップレベルのangularjsモジュールに追加しました)
angular.module('MyAngularJSModule', [
// ...existing imports
])
.directive(
'serviceBootstrap',
downgradeComponent({ component: ServiceBootstrapComponent }) as angular.IDirectiveFactory
)
最後に、このコンポーネントをindex.htmlに入れます。
<body>
<service-bootstrap></service-bootstrap>
<!-- existing body contents -->
</body>
Angularjsがマークアップでそのコンポーネントを見つけると、そのコンポーネントをレンダリングできるようにangularモジュールを初期化する必要があります。これの意図された副作用は、プロバイダーなども初期化されて利用可能になることです通常使用できるdowngradeInjectable
と組み合わせて使用します。
これはangular githubスレッドで指摘されました。
https://github.com/angular/angular/issues/16491#issuecomment-343021511
George Kalpakasの応答:
明確にするために:downgradeInjectable()をdowngradeModule()で使用できますが、特定の制限があります。特に、Angularがブートストラップされるまで、ダウングレードされたインジェクタブルをインジェクトすることはできません。そしてAngularが(非同期に)初めてブートストラップされるとき、ダウングレードされたコンポーネントがしたがって、ダウングレードされたコンポーネント内(つまり、アップグレードされたAngularJSコンポーネント内)でのみ、ダウングレードされたサービスを安全に使用できます。
私はこれが十分に制限していることを知っているので、downgradeInjectable()をまったく使用しないことに決めるかもしれません-できることとできないことをより明確にしたかっただけです。
UpgradeModuleでアップグレードされた注射を使用する場合、同等の制限が当てはまることに注意してください。AngularJSがブートストラップされるまで使用できません。ただし、AngularJSは通常、AngularモジュールのngDoBootstrap()メソッドとAngularJS(Angularとは異なり)のブートストラップで同期的にブートストラップされるため、この制限は通常は気付かれません。
このスレッドの回答は解決策を見つけるのに役立ちましたが、聖杯は含まれていません。
service-boostrap
コンポーネントを作成することはできません。同じエラーTrying to get the Angular injector before bootstrapping an Angular module.
が発生しますservice-bootstrap
コンポーネントを作成するとうまくいきましたが、- githubのこの問題 で説明されているように、Angular composants)内の変更検出に関する問題が発生しました=。@angular/upgrade
ソースコードを編集してfalse
をtrue
に変更し、コンポーネントをゾーンに強制的に作成するよう提案しました。しかし、この場合はパフォーマンスの問題が発生するようです(ユーザーイベントでngZoneのコードが複数回起動されたようです)。service-bootstrap
これを実現するために、少し変更したservice-bootstrap
コンポーネントを作成しました。
import { Component, Output, EventEmitter, AfterViewInit } from "@angular/core";
@Component({
selector: 'service-bootstrap',
template: ``
})
export class ServiceBootstrapComponent implements AfterViewInit{
@Output()
public initialized: EventEmitter<void> = new EventEmitter();
public ngAfterViewInit(){
this.initialized.emit();
}
}
AngularモジュールでこのコンポーネントをentryComponent
として宣言し、downgradeComponent
を呼び出してAngularJSに登録します。
import { downgradeModule, downgradeInjectable, downgradeComponent } from '@angular/upgrade/static';
const bootstrapFn = (extraProviders: StaticProvider[]) => {
const platformRef = platformBrowserDynamic(extraProviders);
return platformRef.bootstrapModule(AppModule);
};
const downgradedModule = downgradeModule(bootstrapFn);
const app = angular.module('ngApp', [
downgradedModule,
'app'
]);
app.directive('serviceBootstrap', downgradeComponent({ component: ServiceBootstrapComponent }));
次に(そして魔法がここで発生します)、新しいAngularJSコンポーネントを作成しました。
angular.module("app")
.directive('ng1App', ng1AppDirective);
function ng1AppDirective(){
return {
template: `
<service-bootstrap (initialized)="onInit()"></service-bootstrap>
<section ng-if="initialized">
<!-- Your previous app's code here -->
</section>
`,
controller: ng1AppController,
scope: {},
};
}
ng1AppController.$inject = ['$scope'];
function ng1AppController($scope){
$scope.onInit = onInit;
$scope.initialized = false;
function onInit(){
$scope.initialized = true;
}
}
次に、私のindex.htmlはこのコンポーネントのみを参照しました
<body>
<ng1-app></ng1-app>
</body>
このアプローチでは、AngularJSコンポーネントをAngularコンポーネント(Angularコンポーネント)の変更検出を壊します)内にネストしていませんが、最初の= Angularコンポーネントは、Angularプロバイダーにアクセスする前にロードされます。
私も同じ問題を抱えていましたが、その理由は上の答えで説明されています。
ダウングレードされたangular $ injector を使用してサービスを動的に注入することにより、これを修正しました。
手順
ダウングレードしたサービスをangularjsモジュールに登録します
angular.module('moduleName', dependencies)
angular.factory('service', downgradeInjectable(Service));
注入$injector
をコントローラーに送信し、これを使用してダウングレードされたサービスを取得します
const service = this.$injector.get('service');
service.methos();
ハイブリッドアプリでも同じエラーが発生しました。次のバージョンを使用しています。
この回答で述べたように、Angularのブーストラッピングを強制するために<ng2-bootstrap>
というダミーコンポーネントも使用しました。次に、Angularがブートストラップされているかどうかを確認するAngularJSサービスを作成しました。
// tslint:disable: max-line-length
/**
* This service can be used in cases where Angular fails with following error message:
*
* `Error: Trying to get the Angular injector before bootstrapping the corresponding Angular module.`
*
* Above error occurs because of how `downgradeModule` works.
*/
/*@ngInject*/
export class Ng2BootstrapDetectionService {
private bootstrapDone = false;
constructor(private $q: ng.IQService) {}
public whenBootstrapDone(): ng.IPromise<void> {
if (this.bootstrapDone) {
return this.$q.resolve();
}
const deferred = this.$q.defer<void>();
angular.element(document).ready(() => {
const intervalId = setInterval(() => {
const el = document.querySelector('ng2-bootstrap');
if (el && el.outerHTML.includes('ng-version=')) {
this.bootstrapDone = true;
clearInterval(intervalId);
deferred.resolve();
}
}, 500);
});
return deferred.promise;
}
}
Ng2BootstrapDetectionService
は以下のように使用できます:
import {NotificationService} from 'ng2-app/notification.service';
// This can be used in cases where you get following error:
// `Error: Trying to get the Angular injector before bootstrapping the corresponding Angular module.`
// You will need access to following
// $injector: AngularJS Injector
// Ng2BootstrapDetectionService: our custom service to check bootsrap completion
this.Ng2BootstrapDetectionService
.whenBootstrapDone()
.then(() => {
const notificationService = this.$injector
.get<NotificationService>('ng2NotificationService');
notificationService.notify('my message!');
});
このソリューションの詳細 は、このブログ投稿の最後にあります 。
私は同じ問題を抱えていましたが、これを見つけるまでに数時間かかりました。私の回避策は、ダウングレードする必要があるすべてのサービスを注入するだけで、何もしないServiceBootstrapComponentを作成することでした。
次に、そのコンポーネントをダウングレードし、@ NgModuleのenエントリとしてマークして、index.htmlに追加します。
私のために働く。