简体   繁体   English

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

[英]How to share service between two modules - @NgModule in angular not between to components?

In my application, I have two different bootstrap module ( @NgModule ) running independently in one application.在我的应用程序中,我有两个不同的引导模块 ( @NgModule ) 在一个应用程序中独立运行。 There are not one angular app bit separate bootstrap module and now I want they should communicate to each other and share data.没有一个角度应用程序位单独的引导程序模块,现在我希望它们应该相互通信并共享数据。

I know through @Injectable service as the provider in the module, I can share data in all component under @NgModule but how I will share data between two different module ( not component inside module ).我知道通过@Injectable服务作为模块中的提供者,我可以在@NgModule下的所有组件中共享数据,但是我将如何在两个不同的模块(不是模块内的组件)之间共享数据。

Is there a way one service object can be accessed in another module?有没有办法可以在另一个模块中访问一个服务对象? Is there a way I can access the object of Service available in browser memory and use it in my other angular module?有没有办法可以访问浏览器内存中可用的服务对象并在我的其他角度模块中使用它?

As per the final version of Angular 2, services provided by a module are available to every other module that imports it.根据 Angular 2 的最终版本,模块提供的服务可用于导入它的每个其他模块。 The Official Style Guide advice that application-wide services (singletons) that are to be reused anywhere in the application should be provided by some Core Module , that is to be imported in the main App Module so it would be injectable everywhere. 官方风格指南建议在应用程序中的任何地方重用的应用程序范围的服务(单例)应该由一些Core Module ,该Core Module将被导入到主App Module以便它可以在任何地方注入。

If you do not use a structure that involves a Core Module with shared singletons, and you are independently developing two NgModules, and you want a service in one of them to be used in the other, then the only solution is to import the provider into the other :如果你不使用涉及共享单例的Core Module的结构,并且你正在独立开发两个NgModules,并且你希望其中一个服务在另一个中使用,那么唯一的解决方案是将提供者导入另一个:

Here's the provider module:这是提供者模块:

/// 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 { }

Here's the other module, that wants to use MyService这是另一个想要使用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 { }

This way, the service should be injectable in any component SomeOtherModule declares, and in SomeModule itself - just ask for it in the constructor:这样,服务应该可以注入到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();
    }
}

If this doesn't answer your question, I invite you to re-formulate it.如果这不能回答您的问题,我邀请您重新制定它。

  1. create shared module创建共享模块

    @NgModule({}) export class SharedModule { static forRoot(): ModuleWithProviders { return { ngModule: SharedModule, providers: [SingletonService] }; } }
  2. in the app module are your parent app module import the shared module like that在应用程序模块中是您的父应用程序模块导入共享模块

    SharedModule.forRoot()
  3. any the children modules if you need to import the shared module import it without the for root任何子模块,如果您需要导入共享模块,请在没有 for root 的情况下导入它

    SharedModule

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

2021-02-03 2021-02-03

In recent Angular versions this is solved using @Injectable({providedIn: 'platform'})在最近的 Angular 版本中,这是使用@Injectable({providedIn: 'platform'})

https://angular.io/api/core/Injectable https://angular.io/api/core/Injectable

Original原创

You can instantiate a service outside Angular and provide a value:你可以在 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 {}

If one application change the state in SharedService or calls a method that causes an Observable to emit a value and the subscriber is in a different application than the emitter, the code in the subscriber is executed in the NgZone of the emitter.如果一个应用程序更改SharedService的状态或调用导致Observable发出值的方法,并且订阅者与发射器位于不同的应用程序中,则订阅者中的NgZone将在发射器的NgZone中执行。

Therefore when subscribing to an observable in SharedService use因此,当订阅SharedService的 observable 时,请使用

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

See also How to dynamically create bootstrap modals as Angular2 components?另请参阅如何将引导模式动态创建为 Angular2 组件?

The answer that Günter Zöchbauer gave is great, however, one issue you may have is that Günter Zöchbauer 给出的答案很好,但是,您可能遇到的一个问题是

window.sharedService

will cause an error in TypeScript.会导致 TypeScript 出错。 You can get around this by replacing all instances of您可以通过替换所有实例来解决此问题

window.sharedService

with

(<any>window).sharedService

I attempted to use the ideas in this answer to share data between multiple bootstrapped modules in my angular application.我尝试使用此答案中的想法在我的 angular 应用程序中的多个引导模块之间共享数据。 The data I was interested in was coming from an http.get() call.我感兴趣的数据来自 http.get() 调用。 It was an expensive call and I wanted to only make the call once and share its results between my 2 bootstrapped modules.这是一个昂贵的调用,我只想调用一次并在我的 2 个引导模块之间共享它的结果。

Initially, I stored the service as a property on my global window object as suggested, but in the end, I decided to use static variables and call publishReplay() on my observable to create a ReplaySubject to replay my emissions to future subscribers.最初,我按照建议将服务作为属性存储在全局窗口对象上,但最后,我决定使用静态变量并在我的 observable 上调用 publishReplay() 来创建一个 ReplaySubject 来向未来的订阅者重播我的排放。 This allowed multiple subscribers to share data and only make the REST call once.这允许多个订阅者共享数据并且只进行一次 REST 调用。

One caveat here... The original question asked how to share one service... This answer does not share one service... Multiple services are created, but the data is shared as the observable is stored in a static variable... That means the observable sticks around as long as your application and because of the call to publishReplay() anyone who subscribes to the observable replays the data previously returned.这里有一个警告......最初的问题是问如何共享一项服务......这个答案不共享一项服务......创建了多个服务,但是由于可观察对象存储在静态变量中而共享数据......这意味着只要您的应用程序并且由于调用publishReplay()任何订阅 observable 的人重放先前返回的数据,observable 就会一直存在。

Here is my code:这是我的代码:

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 || {};
    }

}

Hope this helps.希望这会有所帮助。

I think below is a neat and clean solution.我认为下面是一个整洁干净的解决方案。 I used in many projects.我在很多项目中使用过。

Create a shared module ( AdModule in my case)创建一个共享模块(在我的例子中是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 { }

import AdModule in any module where you want to use shared service ( AdmobService )在要使用共享服务的任何模块中导入AdModule ( AdmobService )

Module1模块1

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

Module 2模块 2

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

You can't use @Günter Zöchbauer's answer if you are injecting any dependency to the service.如果您向服务注入任何依赖项,则不能使用 @Günter Zöchbauer 的回答。 My solution to services that need additional dependencies is assign them to the window object in the service constructor.我对需要附加依赖项的服务的解决方案是将它们分配给服务构造函数中的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;
  }
}

This will ensure there is only one service no matter how service provided on modules.这将确保无论模块上提供的服务如何,都只有一种服务。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM