Angular 2如何为延迟加载的模块提供单例服务

时间:2016-08-18 05:39:09

标签: angular typescript module angular2-services

根据我对Angular 2 rc5的理解,要从另一个模块(不是AppModule)提供服务,作为每个组件的单例,即使是那些延迟加载的,我们也不会将该服务包含在该另一个模块的providers数组中。我们改为使用RouterModule.forRoot()导出它并将结果导入AppModule

According to the docs

  

SharedModule只应在导入时提供UserService   根AppModule。 SharedModule.forRoot方法可以帮助我们实现这一目标   挑战... SharedModule没有providers ...当我们添加时   将SharedModule导入AppModule,我们调用forRoot。在   这样做,AppModule获得了导出的类和   SharedModule同时提供单一UserService提供程序   时间

我真的很挣扎如何使第三方服务(我的imports的{​​{1}}数组中的模块使用的服务)可用于延迟加载的路由。我无法控制这个第三方模块,所以我不能从该模块的AppModule数组中删除该服务,并将其放在NgModule.providers内,就像我使用其中一个服务一样。

具体服务为RouterModule.forRoot()MdIconRegistryproviders MdIconModule。此服务用于注册svg图标,然后可以使用Angular Material 2 alpha 7-3标记显示在页面上。所以:

  • 我在我的根<md-icon svgIcon='iconName'>
  • 中导入了MdIconModule
  • 我使用相关服务在AppModule
  • 中注册svg图标

图标可见且效果很好,但仅限于启动时加载的模块。延迟加载的模块无法看到这些图标,所以我怀疑Angular注入器没有注入AppComponent服务的同一个实例。

tl; dr:如何将第三方模块的服务作为我的延迟加载组件的单例?

Here is a plunker that demonstrates the problem(以MdIconRegistry编码)。

PS:这引起了typescript开发者on github.

的注意

2 个答案:

答案 0 :(得分:9)

I do not think it has anything to do with the component being lazy-loaded.

LazyLoadedComponent不是AppModule的一部分 - 它是LazyModule的一部分。根据文档,组件只能是一个模块的一部分。如果您尝试将LazyLoadedComponent添加到AppModule,则会出现相应的错误。所以LazyLoadedComponent甚至根本没有看到MdIconModule。您可以通过查看调试器中的模板输出来确认这一点 - 它保持不变。

<md-icon svgIcon="play"></md-icon>

解决方案似乎是将MdIconModule添加到LazyModule,虽然仅此一项不能解决问题,但它确实会在输出中添加错误。

  

检索图标时出错:错误:无法找到名称为“:play”的图标

模板输出现在看起来像这样,所以我们知道它正在加载。

<md-icon role="img" svgicon="play" ng-reflect-svg-icon="play" aria-label="play"></md-icon>

我从LazyLoadedComponent添加了对addSvgIconSet的调用,并且它使它工作......所以这证明每个组件有一个MdIconRegistry服务的实例 - 不是你想要的,但可能指向正确的方向。

这是新的插件 - http://plnkr.co/edit/YDyJYu?p=preview

经过进一步审核后,我在docs中找到了这个:

  

为什么延迟加载的模块中提供的服务仅对该模块可见?

     

与启动时加载的模块的提供者不同,延迟加载模块的提供者是模块范围的。

最后更新!这是答案。没有为延迟加载的组件正确设置MdIconModule ......但我们可以轻松创建我们自己的模块,该模块已正确设置并使用它。

import { NgModule } from '@angular/core';
import { HttpModule } from '@angular/http';

import { MdIcon } from '@angular2-material/icon';
import { MdIconRegistry } from '@angular2-material/icon';

@NgModule({
  imports: [HttpModule],
  exports: [MdIcon],
  declarations: [MdIcon]
})
export class MdIconModuleWithProviders {
  static forRoot(): ModuleWithProviders {
    return {
      ngModule: MdIconModuleWithProviders,
      providers: [ MdIconRegistry ]
    };
  }
}

Plunk已更新且完全正常工作。 (对不起,更新了同一个) - &gt; http://plnkr.co/edit/YDyJYu?p=preview

有人可能会提交拉取请求,以便Angular Material导出两种样式的模块。

答案 1 :(得分:0)

Angular 6的新功能有一种将提供程序注册为单例的新方法。在服务的@Injectable()装饰器中,使用providedIn属性。将其值设置为“root”。然后你不需要将它添加到根模块的提供者列表中,或者在这种情况下你也可以将它设置为你的MdIconModuleWithProviders模块:

@Injectable({
  providedIn: MdIconModuleWithProviders // or 'root' for singleton
})
export class MdIconRegistry {
...