如何在两个模块之间共享服务 - angular 中的 @NgModule 而不是组件之间?
How to share service between two modules - @NgModule in angular not between to components?
在我的应用程序中,我在一个应用程序中有两个独立的 bootstrap 模块 (@NgModule
) 运行。没有一个 angular 应用程序位独立 bootstrap 模块,现在我希望它们应该相互通信并共享数据。
我知道通过 @Injectable
服务作为模块中的提供者,我可以在 @NgModule
下的所有组件中共享数据,但是我将如何在两个不同的模块(不是模块内的组件)之间共享数据.
有没有一种方法可以在另一个模块中访问一个服务对象?有没有一种方法可以访问浏览器内存中可用的服务对象并在我的其他 angular 模块中使用它?
2021-02-03
在最近的 Angular 版本中,使用 @Injectable({providedIn: 'platform'})
解决了这个问题
https://angular.io/api/core/Injectable
原创
您可以在 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
}));
}
}
另见
Günter Zöchbauer 给出的答案很好,但是,您可能遇到的一个问题是
window.sharedService
会导致 TypeScript 出错。您可以通过替换
的所有实例来解决此问题
window.sharedService
和
(<any>window).sharedService
根据 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();
}
}
如果这不能回答您的问题,我邀请您重新制定它。
我尝试使用此答案中的想法在我的 angular 应用程序中的多个自举模块之间共享数据。我感兴趣的数据来自 http.get() 调用。这是一个昂贵的调用,我只想调用一次并在我的 2 个自举模块之间共享它的结果。
最初,我按照建议将服务作为 属性 存储在我的全局 window 对象上,但最后,我决定使用静态变量并在我的可观察对象上调用 publishReplay() 以创建一个 ReplaySubject 以向未来的订阅者重播我的排放。这允许多个订阅者共享数据并且只进行一次 REST 调用。
这里有一个警告...最初的问题是问如何共享一项服务...这个答案不共享一项服务...创建了多个服务,但数据是共享的,因为 observable 存储在一个静态变量...这意味着只要您的应用程序存在,并且由于调用 publishReplay()
任何订阅可观察对象的人都会重放先前返回的数据,所以可观察对象会一直存在。
这是我的代码:
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 || {};
}
}
希望对您有所帮助。
创建共享模块
@NgModule({})
export class SharedModule {
static forRoot(): ModuleWithProviders {
return {
ngModule: SharedModule,
providers: [SingletonService]
};
}
}
在应用模块中是你的父应用模块导入共享模块那样
SharedModule.forRoot()
任何子模块,如果你需要导入共享模块,请在不使用 for root 的情况下导入它
SharedModule
https://angular-2-training-book.rangle.io/handout/modules/shared-modules-di.html
我认为下面是一个简洁明了的解决方案。我在很多项目中都用过。
创建共享模块(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
)
模块 1
/// module1.ts
@NgModule({
imports: [
...,
AdModule, // import shared module
],
})
export class Module1 { }
模块 2
/// module2.ts
@NgModule({
imports: [
...,
AdModule, // import shared module
],
})
export class Module2 { }
如果您向服务注入任何依赖项,则不能使用@Günter Zö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;
}
}
无论模块如何提供服务,这将确保只有一项服务。
在我的应用程序中,我在一个应用程序中有两个独立的 bootstrap 模块 (@NgModule
) 运行。没有一个 angular 应用程序位独立 bootstrap 模块,现在我希望它们应该相互通信并共享数据。
我知道通过 @Injectable
服务作为模块中的提供者,我可以在 @NgModule
下的所有组件中共享数据,但是我将如何在两个不同的模块(不是模块内的组件)之间共享数据.
有没有一种方法可以在另一个模块中访问一个服务对象?有没有一种方法可以访问浏览器内存中可用的服务对象并在我的其他 angular 模块中使用它?
2021-02-03
在最近的 Angular 版本中,使用 @Injectable({providedIn: 'platform'})
https://angular.io/api/core/Injectable
原创
您可以在 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
}));
}
}
另见
Günter Zöchbauer 给出的答案很好,但是,您可能遇到的一个问题是
window.sharedService
会导致 TypeScript 出错。您可以通过替换
的所有实例来解决此问题window.sharedService
和
(<any>window).sharedService
根据 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();
}
}
如果这不能回答您的问题,我邀请您重新制定它。
我尝试使用此答案中的想法在我的 angular 应用程序中的多个自举模块之间共享数据。我感兴趣的数据来自 http.get() 调用。这是一个昂贵的调用,我只想调用一次并在我的 2 个自举模块之间共享它的结果。
最初,我按照建议将服务作为 属性 存储在我的全局 window 对象上,但最后,我决定使用静态变量并在我的可观察对象上调用 publishReplay() 以创建一个 ReplaySubject 以向未来的订阅者重播我的排放。这允许多个订阅者共享数据并且只进行一次 REST 调用。
这里有一个警告...最初的问题是问如何共享一项服务...这个答案不共享一项服务...创建了多个服务,但数据是共享的,因为 observable 存储在一个静态变量...这意味着只要您的应用程序存在,并且由于调用 publishReplay()
任何订阅可观察对象的人都会重放先前返回的数据,所以可观察对象会一直存在。
这是我的代码:
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 || {};
}
}
希望对您有所帮助。
创建共享模块
@NgModule({}) export class SharedModule { static forRoot(): ModuleWithProviders { return { ngModule: SharedModule, providers: [SingletonService] }; } }
在应用模块中是你的父应用模块导入共享模块那样
SharedModule.forRoot()
任何子模块,如果你需要导入共享模块,请在不使用 for root 的情况下导入它
SharedModule
https://angular-2-training-book.rangle.io/handout/modules/shared-modules-di.html
我认为下面是一个简洁明了的解决方案。我在很多项目中都用过。
创建共享模块(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
)
模块 1
/// module1.ts
@NgModule({
imports: [
...,
AdModule, // import shared module
],
})
export class Module1 { }
模块 2
/// module2.ts
@NgModule({
imports: [
...,
AdModule, // import shared module
],
})
export class Module2 { }
如果您向服务注入任何依赖项,则不能使用@Günter Zö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;
}
}
无论模块如何提供服务,这将确保只有一项服务。