the*_*Owl 12 javascript ng-upgrade angular
对于角度5.0,升级模块现在可以选择使用downgradeModule,它在角度区域之外运行angularjs.在试验这个时,我遇到了使用downgradeInjectable的问题.
我收到错误:
未捕获错误:在引导Angular模块之前尝试获取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 ),
] );
Run Code Online (Sandbox Code Playgroud)
然而...
由于bootladpping是在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,
) {}
}
Run Code Online (Sandbox Code Playgroud)
降级注射尝试
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;
Run Code Online (Sandbox Code Playgroud)
当"downgradeInjectable(MyService)运行时,角度注入器尚未可用,因为角度尚未被引导.因此错误:
未捕获错误:在引导Angular模块之前尝试获取Angular注入器.
有谁知道如何解决这个问题?
这是在一个有角度的github线程中向我指出的。
https://github.com/angular/angular/issues/16491#issuecomment-343021511
乔治·卡尔帕卡斯(George Kalpakas)的回应:
需要明确说明的是:可以将downgradeInjectable()与downgradeModule()结合使用,但是有一些限制。特别是,在启动Angular之前,您不能尝试注入降级的注入物。第一次渲染降级的组件时,Angular被引导(异步)。因此,您只能在降级的组件内(即在升级的AngularJS组件内)安全地使用降级的服务。
我知道这样做的局限性足以让您决定根本不使用downgradeInjectable()-只是想更清楚地说明您可以做什么和不能做什么。
请注意,当使用带有UpgradeModule的升级注射剂时,等效限制为true:在启动AngularJS之前,不能使用它。但是,通常不会注意到此限制,因为AngularJS通常在Angular模块的ngDoBootstrap()方法中引导,并且AngularJS(与Angular不同)是同步引导程序。
注意:下面的答案遵循将angular 1.x称为angularjs而所有angular 2+版本称为简单角度的约定.
扩展JGoodgive上面的答案,基本上,如果你正在使用downgradeModule,那么当需要渲染第一个角度分量时,角度模块会被angularjs懒散地自我引导.在此之前,由于角度模块未初始化,如果您正在使用angularjs中的任何角度服务downgradeInjectable,则这些服务也不可用.
解决方法是尽早强制启动角度模块.为此,需要一个简单的组件:
import {Component} from '@angular/core';
@Component({
selector: 'service-bootstrap'
template: ''
})
export class ServiceBootstrapComponent {}
Run Code Online (Sandbox Code Playgroud)
该组件不执行任何操作.现在,我们在顶级角度模块中声明此组件.
@NgModule({
// ...providers, imports etc.
declarations: [
// ... existing declarations
ServiceBootstrapComponent
],
entryComponents: [
// ... existing entry components
ServiceBootstrapComponent
]
})
export class MyAngularModule {}
Run Code Online (Sandbox Code Playgroud)
接下来,我们还需要将此组件的降级版本添加到angularjs模块.(我把它添加到了顶级angularjs模块中)
angular.module('MyAngularJSModule', [
// ...existing imports
])
.directive(
'serviceBootstrap',
downgradeComponent({ component: ServiceBootstrapComponent }) as angular.IDirectiveFactory
)
Run Code Online (Sandbox Code Playgroud)
最后,我们在index.html中引入了这个组件.
<body>
<service-bootstrap></service-bootstrap>
<!-- existing body contents -->
</body>
Run Code Online (Sandbox Code Playgroud)
当angularjs在标记中找到该组件时,它需要初始化角度模块以便能够呈现该组件.这样做的预期副作用是提供者等也被初始化并且可以使用downgradeInjectable,这可以正常使用.
此主题中的答案帮助我找到了解决方案,但没有一个包含圣杯:
service-boostrap除了AngularJS之外,Angular是异步加载的,因此无法在应用程序的代码旁边创建组件。这给出了相同的错误Trying to get the Angular injector before bootstrapping an Angular module.service-bootstrap包装了AngularJS代码的组件的工作原理,但是随后我遇到了Angular组合者内部的变更检测问题,如github上的问题所述。@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();
}
}
Run Code Online (Sandbox Code Playgroud)
将此组件声明为entryComponentAngular模块中的组件,并调用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 }));
Run Code Online (Sandbox Code Playgroud)
然后(魔术发生在这里),我创建了一个新的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;
}
}
Run Code Online (Sandbox Code Playgroud)
然后,我的index.html仅引用了此组件
<body>
<ng1-app></ng1-app>
</body>
Run Code Online (Sandbox Code Playgroud)
使用这种方法,我没有将AngularJS组件嵌套在Angular组件内(这会中断Angular组件中的更改检测),并且仍然确保在访问Angular提供程序之前已加载第一个Angular组件。
| 归档时间: |
|
| 查看次数: |
5030 次 |
| 最近记录: |