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

As per the final version of Angular 2, services provided by a module are available to every other module that imports it. 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.

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 :

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

/// 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:

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

    SharedModule
    

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


2021-02-03

In recent Angular versions this is solved using @Injectable({providedIn: 'platform'})

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

Original

You can instantiate a service outside Angular and provide a value:

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.

Therefore when subscribing to an observable in SharedService use

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?