46

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

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

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

4

7 回答 7

57

根据 Angular 2 的最终版本,一个模块提供的服务可用于导入它的所有其他模块。官方样式指南建议,要在应用程序中的任何地方重用的应用程序范围的服务(单例)应该由 some 提供Core Module,即在 main 中导入,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();
    }
}

如果这不能回答您的问题,我邀请您重新制定它。

于 2016-11-13T17:27:17.117 回答
21
  1. 创建共享模块

    @NgModule({})
    export class SharedModule {
        static forRoot(): ModuleWithProviders {
            return {
                ngModule: SharedModule,
                providers: [SingletonService]
            };
        }
    }
    
  2. 在应用程序模块中是您的父应用程序模块,像这样导入共享模块

    SharedModule.forRoot()
    
  3. 如果您需要导入共享模块,则任何子模块都可以在没有 for root 的情况下导入它

    SharedModule
    

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

于 2018-01-15T11:30:18.977 回答
11

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或调用导致 anObservable发出值的方法,并且订阅者位于与发射器不同的应用程序中,则订阅者中的代码在发射器中执行NgZone

因此,当订阅一个SharedService使用中的可观察对象时

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

另请参阅如何将引导模式动态创建为 Angular2 组件?

于 2016-10-17T15:01:17.197 回答
3

Günter Zöchbauer 给出的答案很好,但是,您可能遇到的一个问题是

window.sharedService

会导致 TypeScript 出错。您可以通过替换所有实例来解决此问题

window.sharedService

(<any>window).sharedService
于 2016-10-20T16:45:04.853 回答
1

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

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

这里有一个警告......最初的问题是如何共享一项服务......这个答案不共享一个服务......创建了多个服务,但数据是共享的,因为可观察对象存储在静态变量中......这意味着只要您的应用程序和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 || {};
    }

}

希望这可以帮助。

于 2017-06-11T21:00:23.507 回答
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)

模块1

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

模块 2

/// module2.ts
@NgModule({
  imports: [
    ...,
    AdModule, // import shared module
  ],
})
export class Module2 { }
于 2019-10-24T07:43:44.167 回答
1

如果您向服务注入任何依赖项,则不能使用@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;
  }
}

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

于 2020-07-10T01:18:09.967 回答