将具有共享服务的多个角度应用程序的条件boostrap迁移到嵌套的ngModule

Tom*_*Tom 5 angular

问题

我正在将RC4迁移到RC5,到目前为止它仍然有效,但是因为我必须调整引导程序,无论如何我想知道是否有人为我的引导程序(可能使用ngModules)有一个更清洁的解决方案,因为对我来说它感觉有点hackish.

基本上它会引导多个组件,这些组件并不总是存在,具体取决于它们是否在页面上,并确保组件及其子组件之间共享配置/帮助程序.我可以直接将3个组件包装到ngModules中,但是我仍然需要将共享服务注入模块.有没有办法将所有3个组件包装到一个模块中,只有当它们在页面上可用时才引导它们?我也没有在ngModule中看到一个init钩子,我可以在将它们注入子组件之前预先配置它们.

这是我以前的main.ts中的相关部分:

var cs = new ConfigurationService();
var hs = new HelperService(cs);
var injector = ReflectiveInjector.resolveAndCreate([TranslateService,
    {provide: TranslateLoader, useClass: JsonLoader}, HTTP_PROVIDERS]);
var ts = injector.get(TranslateService);

ts.setDefaultLang('en');
ts.use(cs.getLanguage());

var defaultProviders = [
    {provide: TranslateService, useValue: ts},
    {provide: ConfigurationService, useValue: cs},
    {provide: HelperService, useValue: hs}
];

if ($('notification-widget').length > 0) {
    bootstrap(NotificationWidgetComponent, defaultProviders);
}

if ($('livesearch-widget').length > 0){
    bootstrap(LivesearchWidgetComponent, defaultProviders);
}

if ($('enterprise-search').length > 0){
    bootstrap(EnterpriseSearchComponent, defaultProviders);
}
Run Code Online (Sandbox Code Playgroud)

部分解决方案

我找到了一种翻译概念的方法:

main.ts很简单,如文档所述:

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule }              from './app/app.module';

platformBrowserDynamic().bootstrapModule(AppModule);
Run Code Online (Sandbox Code Playgroud)

模块本身不使用引导程序注释,因为这不能有条件地完成,您可以只使用声明,因此angular知道潜在的起点并手动实现引导程序:

@NgModule({
    imports: [ BrowserModule ],
    declarations: [ NotificationWidgetComponent, LivesearchWidgetComponent, EnterpriseSearchComponent ],
    providers: [ConfigurationService, HelperService, TranslateService,
        {provide: TranslateLoader, useClass: JsonLoader}]
})
export class AppModule {
    constructor(
        private conf: ConfigurationService,
        private trans: TranslateService,
        private help: HelperService
    ){
        this.trans.setDefaultLang('en');
        this.trans.use(this.conf.getLanguage());
    }

    ngDoBootstrap(){
        let providers = [
            {provide: ConfigurationService, useValue: this.conf},
            {provide: HelperService, useValue: this.help},
            {provide: TranslateService, useValue: this.trans}
        ];

        if ($('notification-widget').length > 0) {
            bootstrap(NotificationWidgetComponent, providers);
        }

        if ($('livesearch-widget').length > 0){
            bootstrap(LivesearchWidgetComponent, providers);
        }

        if ($('enterprise-search').length > 0){
            bootstrap(EnterpriseSearchComponent, providers);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

可以在模块构造函数中处理服务配置,并像以前一样手动完成注入.然而,bootstrap方法被删除,所以我将ngDoBootstrap的最后一部分更改为此(仅作为测试,忽略上面的两个):

    if ($('enterprise-search').length > 0){
      platformBrowserDynamic().bootstrapModule(EnterpriseSearchModule, {providers: providers});
    }
Run Code Online (Sandbox Code Playgroud)

模块本身很简单:

@NgModule({
    imports: [ BrowserModule ],
    declarations: [ EnterpriseSearchComponent ],
    bootstrap: [ EnterpriseSearchComponent ]
})
export class EnterpriseSearchModule { }
Run Code Online (Sandbox Code Playgroud)

我现在遇到的问题是,自动引导组件无法解析配置服务,尽管它明确地作为提供程序提供给包装模块.这对我来说似乎是一个有角色的错误,或者我只是做错了什么?

gdi*_*290 1

生命周期钩子ngDoBootstrap不是这样工作的。你所期望的是类似的东西ngOnBootstrapngAfterBootstrap或者ngOnInit它们都不能在 NgModule 上工作。因为ngDoBootstrap你想做的是

ngDoBootstrap(moduleRef) {
  const appRef = moduleRef.injector.get(ApplicationRef);
  // somehow grab compFactory probably from entryComponents
  // bootstrap each entryCoponent
  appRef.bootstrap(compFactory);
}
Run Code Online (Sandbox Code Playgroud)

但有一个问题,因为ApplicationRef#bootstrap它不再需要注入器或提供者。您最好在 NgModule 之外执行此操作,并为每个应用程序创建一个 NgModule。或者在 ngDoBootstrap 中使用 Di 来获取您的服务,这样它是在引导期间而不是稍后创建的 moduleRef.injector.get(MyService); // this makes sure that the service is created during bootstrap rather than later when something else injects it