web-dev-qa-db-ja.com

2つのモジュール間でサービスを共有する方法-コンポーネント間ではなくangularの@NgModule?

私のアプリケーションでは、1つのアプリケーションで2つの異なるbootstrapモジュール(@NgModule)が独立して実行されています。 angular appビットで分離されたbootstrapモジュールは1つではなく、相互に通信してデータを共有する必要があります。

モジュールのプロバイダーとして@Injectableサービスを通じて、@NgModuleの下のすべてのコンポーネントでデータを共有できますが、2つの異なるモジュール(モジュール内のコンポーネントではない)間でデータを共有する方法を知っています。

別のモジュールで1つのサービスオブジェクトにアクセスする方法はありますか?ブラウザのメモリで利用可能なサービスのオブジェクトにアクセスし、他のangularモジュールで使用する方法はありますか?

35
Aniruddha Das

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

1つのアプリケーションがSharedServiceの状態を変更するか、Observableに値を発行させるメソッドを呼び出し、サブスクライバーがエミッターとは異なるアプリケーションにある場合、サブスクライバーのコードはエミッターのNgZoneで実行されます。

したがって、SharedServiceのobservableにサブスクライブする場合に使用します

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

Angular2コンポーネントとしてbootstrapモーダルを動的に作成する方法? も参照してください。

8

Angular 2の最終バージョンでは、モジュールによって提供されるサービスは、それをインポートする他のすべてのモジュールで利用できます。 Official Style Guide アプリケーション全体のどこでも再利用されるアプリケーション全体のサービス(シングルトン)は、いくつかのCore Moduleによって提供されるべきであり、メインのApp Moduleにインポートされるため、注入可能になるどこにでも。

共有シングルトンを持つコアモジュールを含む構造を使用せず、2つの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();
    }
}

それでも問題が解決しない場合は、再定式化してください。

47
FacelessPanda
  1. 共有モジュールを作成する

    @NgModule({})
    export class SharedModule {
        static forRoot(): ModuleWithProviders {
            return {
                ngModule: SharedModule,
                providers: [SingletonService]
            };
        }
    }
    
  2. アプリモジュールには、親アプリモジュールがそのような共有モジュールをインポートします

    SharedModule.forRoot()
    
  3. 共有モジュールをインポートする必要がある場合は、子モジュール

    SharedModule
    

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

14
Hager Aly

この回答のアイデアを使用して、angularアプリケーション内の複数のブートストラップモジュール間でデータを共有しようとしました。私が興味を持っていたデータは、http.get()呼び出しからのものでした。高価な呼び出しでしたので、呼び出しを1回だけ行い、その結果を2つのブートストラップされたモジュール間で共有したかったのです。

最初に、提案されたようにグローバルウィンドウオブジェクトのプロパティとしてサービスを保存しましたが、最終的に、静的変数を使用し、observableでpublishReplay()を呼び出してReplaySubjectを作成し、将来のサブスクライバーに放出を再生することにしました。これにより、複数のサブスクライバーがデータを共有し、REST呼び出しを1回だけ行うことができました。

ここで1つの警告...元の質問は1つのサービスを共有する方法を尋ねました...この回答は1つのサービスを共有しません...複数のサービスが作成されますが、オブザーバブルが静的変数に格納されるためデータが共有されます...つまり、オブザーバブルは、アプリケーションと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 || {};
    }

}

お役に立てれば。

1
birwin

GünterZöchbauerの答えは素晴らしいですが、あなたが抱えているかもしれない問題の1つは

window.sharedService

typeScriptでエラーが発生します。これを回避するには、すべてのインスタンスを置き換えます

window.sharedService

(<any>window).sharedService
1
Ryan Anderson