如何在两个模块之间共享服务 - @NgModule在角度之间而不是在组件之间?

时间:2016-10-17 14:40:40

标签: angular angular2-services angular2-modules

在我的应用程序中,我有两个不同的引导程序模块(@NgModule)在一个应用程序中独立运行。没有一个角度app位单独的bootstrap模块,现在我希望他们应该相互通信并共享数据。

我知道通过@Injectable服务作为模块中的提供者,我可以在@NgModule下的所有组件中共享数据,但我将如何在两个不同模块(不是模块内部组件)之间共享数据。 / p>

有没有办法在另一个模块中访问一个服务对象?有没有办法可以访问浏览器内存中可用的服务对象并在我的其他角度模块中使用它?

7 个答案:

答案 0 :(得分:47)

根据Angular 2的最终版本,模块提供的服务可供导入它的每个其他模块使用。 Official Style Guide建议应该在应用程序中的任何位置重用的应用程序范围的服务(单例)应该由某些Core Module提供,即要在主App Module中导入,以便它会在任何地方注射。

如果您不使用涉及具有共享单例的核心模块的结构,并且您要独立开发两个NgModule,并且您希望其中一个服务在另一个中使用,则唯一的解决方案是导入提供者到另一个:

这是提供者模块:

/// some.module.ts
import { NgModule } from '@angular/core';

import { SomeComponent }   from './some.component';

@NgModule({
    imports: [],
    exports: [],
    declarations: [SomeComponent],
    providers: [ MyService ], // <======================= PROVIDE THE SERVICE
})
export class SomeModule { }

这是另一个想要使用MyService

的模块
/// some-other.module.ts
import { NgModule } from '@angular/core';

import { SomeModule } from 'path/to/some.module'; // <=== IMPORT THE JSMODULE

import { SomeOtherComponent }   from './some.other.component';

@NgModule({
    imports: [ SomeModule ], // <======================== IMPORT THE NG MODULE
    exports: [],
    declarations: [SomeOtherComponent],
    providers: [],
})
export class SomeOtherModule { }

这样,服务应该可以在任何组件SomeOtherModule声明中注入,而在SomeModule本身 - 只需在构造函数中请求它:

/// some-other.module.ts

import { MyService } from 'path/to/some.module/my-service';

/* ...
    rest of the module
*/

export class SomeOtherModule {
    constructor( private _myService: MyService) { <====== INJECT THE SERVICE
        this._myService.dosmth();
    }
}

如果这没有回答你的问题,我邀请你重新制定它。

答案 1 :(得分:12)

  1. 创建共享模块

    @NgModule({})
    export class SharedModule {
        static forRoot(): ModuleWithProviders {
            return {
                ngModule: SharedModule,
                providers: [SingletonService]
            };
        }
    }
    
  2. app模块中的
  3. 是您的父app模块导入共享模块

    SharedModule.forRoot()
    
  4. 任何子模块如果您需要导入共享模块,请导入它而不使用for root

    SharedModule
    
  5. https://angular-2-training-book.rangle.io/handout/modules/shared-modules-di.html

答案 2 :(得分:7)

您可以在Angular之外实例化服务并提供值:

class SharedService {
  ...
}
window.sharedService = new SharedService();

@NgModule({
  providers: [{provide: SharedService, useValue: window.sharedService}],
  ...
})
class AppModule1 {}

@NgModule({
  providers: [{provide: SharedService, useValue: window.sharedService}],
  ...
})
class AppModule2 {}

如果一个应用程序更改SharedService中的状态或调用导致Observable发出值的方法,并且订阅者与发射器位于不同的应用程序中,则会执行订户中的代码在发射器的NgZone中。

因此,在SharedService使用

订阅观察者时
class MyComponent {
  constructor(private zone:NgZone, private sharedService:SharedService) {
    sharedService.someObservable.subscribe(data => this.zone.run(() => {
      // event handler code here
    }));
  }
}

另见How to dynamically create bootstrap modals as Angular2 components?

答案 3 :(得分:1)

GünterZöchbauer给出的答案很棒,但是,你可能遇到的一个问题是

window.sharedService

会在TypeScript中导致错误。你可以通过替换

的所有实例来解决这个问题
window.sharedService

(<any>window).sharedService

答案 4 :(得分:1)

我尝试使用此答案中的想法在我的角度应用程序中的多个引导模块之间共享数据。我感兴趣的数据来自http.get()调用。这是一个昂贵的电话,我只想拨打一次电话,并在我的2个自举模块之间分享它的结果。

最初,我按照建议将服务存储为我的全局窗口对象的属性,但最后,我决定使用静态变量并在我的observable上调用publishReplay()来创建一个ReplaySubject,以便将我的排放重放给未来的订阅者。这允许多个订阅者共享数据,并且只进行一次REST调用。

这里有一点需要注意......最初的问题是如何共享一个服务...这个答案不共享一个服务...创建了多个服务,但是当observable存储在静态变量中时数据被共享......这意味着只要您的应用程序以及publishReplay()任何订阅了observable的人都会重新调用之前返回的数据,那么observable就会一直存在。

这是我的代码:

import { Injectable } from '@angular/core';
import { Observable, ReplaySubject } from 'rxjs/Rx';
import { Http } from '@angular/http';

@Injectable()
export class InitService {

    static observable: Observable<number> = null;

    constructor(private http: Http) {}

    getInitData(): Observable<number> {
        if (InitService.observable == null) {
            InitService.observable = this.http.get('api/Init')
                .map(this.extractData)
                .publishReplay()
                .refCount()
                .catch(this.handleError);
        }
        return InitService.observable;
    }


    extractData(res: Response) {
        let body: any = res.json();
        return body || {};
    }

}

希望这有帮助。

答案 5 :(得分:1)

我认为下面是一个干净整洁的解决方案。我曾在许多项目中使用过。

创建一个共享模块(在我的情况下为AdModule

/// ad.module.ts

import ...

// create shared service(AdmobService in my case) object, pass constructor params (if you required)
const admobService = new AdmobService(new AdMobFree(), new InAppPurchase()); 

@NgModule({
  providers: [
    ...,
    { provide: AdmobService, useValue: admobService }, //  use shared service here like this
  ]
})
export class AdModule { }

在要使用共享服务(AdModule)的任何模块中导入AdmobService

Module1

/// module1.ts
@NgModule({
  imports: [
    ...,
    AdModule, // import shared module
  ],
})
export class Module1 { }

模块2

/// module2.ts
@NgModule({
  imports: [
    ...,
    AdModule, // import shared module
  ],
})
export class Module2 { }

答案 6 :(得分:0)

如果您要对服务注入任何依赖,则不能使用@GünterZöchbauer的答案。 对于需要其他依赖项的服务,我的解决方案是将它们关联到服务构造函数中的window对象。

export class MyService {
  private Cahces = {};
  constructor(protected http: HttpClient, private logger: LogService) {
    if (!(<any>window).myService) {
      (<any>window).myService = this;
    }
    return (<any>window).myService;
  }
}

无论模块上如何提供服务,这将确保仅提供一项服务。