0
votes

From Angular Doc, the def about "imports" in NgModule is:

Specifies a list of modules whose exported directives/pipes should be available to templates in this module.

And "providers":

Defines the set of injectable objects that are available in the injector of this module.

So here is the question, when I want to use a 3rd service packed in a 3rd module, should I import the module in "imports", or register the particular service, in "providers"?

3
The answer is yes. You actually want your module to import the service, as well as provide it. You provide it for any components listed in that module under imports as wellZ. Bagley

3 Answers

1
votes

In general, all services added to the providers array of any module are application-wide singletons - meaning they are added to the root injector automatically. There is no need to explicitly add them to the providers array of your AppModule.

That means that when you import a module (or another module imports a module) that has the providers array populated, the services they provide can be injected into any injectable constructor - regardless of where it is. Just import the service, and add it to an injectable constructor.

Now, I say "in general" because for the most part that's true. The only case where it is different is when the module is a lazy loaded module (i.e. loading lazy-loaded routes). Lazy-loaded modules have their own root scope. If you treat that as the exception, it all makes sense.

So to answer your question:

  1. Prefer module.forRoot() if it has such a method. This returns a module with services, which will get bootstrapped with the root injector.

    @NgModule({
        // forRoot ensures that services are added to root injector
        imports: [ThirdPartyModule.forRoot()],
        exports: [],
        declarations: [...],
        providers: [],
    })
    export class AppModule{ }
    
  2. If there is no "forRoot" method, then just import the module into AppModule. Likely, the module has services intended to be registered with the root injector.

    @NgModule({
        imports: [ThirdPartyModule],
        exports: [],
        declarations: [...],
        providers: [],
    })
    export class AppModule{ }
    
  3. If you need to import the module from a FeatureModule (or a SharedModule) because you want to leverage the components, directives, and pipes contained within it, you should use the forChild() method if it has one.

    @NgModule({
        // does not include any services. You still need to import
        // .forRoot() in the AppModule
        imports: [ThirdPartyModule.forChild()],
        exports: [],
        declarations: [...],
        providers: [],
    })
    export class FeatureModule { }
    
  4. If the author of the module has not provided a forRoot() or forChild() method, it may be it was never intended to be imported by any module other than the AppModule.

  5. The author of the module may have decided to include services in the module, but by default chose not to add it to the providers array. In that case its up to you to add it to a providers array of a module (services will have root scope), or add it to a component's providers array (services will have component scope).

0
votes

when I want to use a 3rd service packed in a 3rd module, should I import the module in "imports", or register the particular service, in "providers"?

You can import the module that provides a service.

0
votes

Create a shared/core modules and include all the common modules in providers array of that module and import that module wherever required.
Else its better to inculde only the service than the whole module. Its just the use case.

import {
  ModuleWithProviders, NgModule,
  Optional, SkipSelf
} from '@angular/core';
import { CommonModule } from '@angular/common';

import { SharedService, AuthenticationService, AuthBlockService, LocalStorageService } from './services/index';
@NgModule({
  imports: [CommonModule],
  providers: [SharedService, AuthenticationService, LocalStorageService, AuthBlockService]
})
export class CoreModule {

  constructor( @Optional() @SkipSelf() parentModule: CoreModule) {
    if (parentModule) {
      throw new Error(
        'CoreModule is already loaded. Import it in the AppModule only');
    }
  }


}

and use this core modules in the root modules inside imports array.