使用角度5.0,升级模块现在可以选择使用downgradeModule,它在角度区域之外运行angularjs。在尝试这个时,我遇到了使用downgradeInjectable的问题。
我收到错误:
未捕获错误:在引导Angular模块之前尝试获取Angular注入器。
角度js中的自举角度正常
import requests
def get_weather_json(city, country):
R = requests.get("http://api.openweathermap.org/data/2.5/weather?q=" + city + "," + country + "&appid=xxx")
return R.json()
然而...
由于在初始化angularjs之后进行自举,我不能再使降级注射工作。
要降级的服务
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 ),
] );
降级可注射尝试次数
import { Injectable, Inject, OnInit } from '@angular/core';
@Injectable()
export class MobileService implements OnInit{
constructor(
@Inject( 'angularjsDependency1' ) public angularjsDependency1 : any,
@Inject( 'angularjsDependency2' ) public angularjsDependency2 : any,
) {}
}
当“downgradeInjectable(MyService)运行时,角度注入器尚未可用,因为角度尚未被引导。因此错误:
未捕获错误:在引导Angular模块之前尝试获取Angular注入器。
有没有人知道如何解决这个问题?
答案 0 :(得分:7)
注意:下面的答案遵循将angular 1.x称为angularjs而将所有angular 2+版本称为简单角度的惯例。
扩展JGoodgive上面的答案,基本上,如果你正在使用downgradeModule
,那么当需要渲染第一个角度分量时,angularjs会懒散地自行训练角度模块。在此之前,由于角度模块未初始化,如果您使用downgradeInjectable
访问angularjs内的任何角度服务,则这些服务也不可用。
解决方法是尽早强制启动角度模块。为此,需要一个简单的组件:
import {Component} from '@angular/core';
@Component({
selector: 'service-bootstrap'
template: ''
})
export class ServiceBootstrapComponent {}
这个组件没有做任何事情。现在,我们在顶级角度模块中声明此组件。
@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在标记中找到该组件时,它需要初始化角度模块以便能够呈现该组件。这样做的预期副作用是提供者等也被初始化,并且可以与downgradeInjectable
一起使用,这可以正常使用。
答案 1 :(得分:6)
这是在一个有角度的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不同)bootstraps中同步引导。
答案 2 :(得分:4)
此主题中的答案帮助我找到了解决方案,但没有一个包含圣杯:
service-boostrap
组件是行不通的,因为与AngularJS不同,Angular是异步加载的。这给出了相同的错误Trying to get the Angular injector before bootstrapping an Angular module.
service-bootstrap
组件来包装AngularJS代码,但是,然后我遇到了this issue on github中所述的Angular构成者内部的更改检测问题。@angular/upgrade
源代码,以将false
更改为true
,以强制在区域中创建组件。但是在这种情况下,这似乎会导致性能问题(它似乎在用户事件上多次启动ngZone的代码)service-bootstrap
的第一个角度组件之后创建使用Angular服务的AngularJS组件。为此,我创建了一个经过稍微修改的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组件。
答案 3 :(得分:0)
我遇到了同样的问题,在发现这个问题之前几个小时就搞砸了。 我的解决方法是创建一个ServiceBootstrapComponent,它只会注入我们需要降级的所有服务。
然后我降级该组件,将其标记为@NgModule中的条目并将其添加到index.html。
适合我。
答案 4 :(得分:0)
我有同样的问题,原因在上面的答案中得到了解释。
我通过使用$injector动态注入降级的角度服务来解决此问题。
步骤
将降级的服务注册到angularjs模块
angular.module('moduleName', dependencies)
angular.factory('service', downgradeInjectable(Service));
向您的控制器注入$injector
并使用它来获得降级的服务
const service = this.$injector.get('service');
service.methos();
答案 5 :(得分:0)
我在混合应用程序中遇到了同样的错误。我们正在使用以下版本:
如in this answer所述,我还使用了一个名为<ng2-bootstrap>
的虚拟组件来强制Angular加速。然后,我创建了一个AngularJS服务,用于检查Angular是否已被引导:
// 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!');
});
您可以找到有关此解决方案at the end of this blog post的更多详细信息。