首页 文章

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

提问于
浏览
6

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

According to the docs

SharedModule应该仅在根AppModule导入时提供UserService . SharedModule.forRoot方法帮助我们应对这一挑战...... SharedModule没有提供者......当我们将SharedModule添加到AppModule的导入时,我们调用forRoot . 这样,AppModule获得导出的类,SharedModule同时提供单例UserService提供程序

我真的很挣扎如何为延迟加载的路由提供第三方服务(我的 AppModuleimports 数组中的模块使用的服务) . 我无法控制这个第三方模块,因此我不能只从该模块的 NgModule.providers 数组中删除该服务,并将其放在 RouterModule.forRoot() 中,就像我使用其中一个服务一样 .

具体服务是 MdIconRegistryMdIconModuleAngular Material 2 alpha 7-3providers . 此服务用于注册svg图标,然后可以使用 <md-icon svgIcon='iconName'> 标记在页面上显示该图标 . 所以:

  • 我在我的根 AppModule 导入了 MdIconModule

  • 我使用了相关服务在我的 AppComponent 中注册了svg图标

该图标可见并且运行良好,但仅限于启动时加载的模块 . 延迟加载的模块无法看到这些图标,因此我怀疑Angular注入器没有注入 MdIconRegistry 服务的同一实例 .

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

Here is a plunker that demonstrates the problem(编码于 typescript ) .

PS:这刚引起了 MdIconModule 开发人员的注意on github.

2 回答

  • 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

    经过进一步审核,我在_1713963中发现了这个:

    为什么延迟加载的模块中提供的服务仅对该模块可见?与启动时加载的模块的提供者不同,延迟加载的模块的提供者是模块范围的 .

    最后更新!这是答案 . 没有为延迟加载的组件正确设置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更新并完全正常工作 . (对不起,更新了同一个) - > http://plnkr.co/edit/YDyJYu?p=preview

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

  • 0

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

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

相关问题