简体   繁体   中英

Angular: where do I put services used by multiple modules

I just started using the feature module + lazily loaded routing part of angular framework, and have a bit of trouble getting used to the nuances. One thing that comes up now and again is how to store the services and interfaces- should they go in the providers array of only the modules that use them? or should some kind of main service module be injected into the root module?

I have understood from various tutorials that services and interfaces should not go in the core module or shared module.

what i was doing before hand:

//service.module.ts
@NgModule({
    imports: [],
    exports: [],
    declarations: [],
    providers: [],
})
export class ServicesModule {
    static forRoot(): ModuleWithProviders<ServicesModule> {
        return {
            ngModule: ServicesModule,
            providers: [
              all the services
              provided in our application
            ]
        }
    }
}
// then in app.module.ts
imports: [
    ServicesModule.forRoot(),
]

so my choices are

  1. leave set up as-is, have a collective directory called 'services' in app folder, and use constructor DI in components that need a service. likewise with models/interfaces, import them from a directory called 'models'.
  2. move services into modules that need them and only provide shared services in the ServicesModule, helping with lazy loading of modules.

I guess a different/easier question is, if i move all my services back into the provider array of my app.module, would this simplify things? Seems counter intuitive.

If you put these all in a services module & import that in AppModule then it behaves the same as Injectable({ providedIn: 'root' }) . Which there's nothing wrong with marking a service as providedIn: 'root' if it does need to be globally accessable, plus Angular will still lazy load in some way where an instance of that root-provided service will not be created if nothing ever injects it. The main thing is that there will be only one instance of the service created & shared between everything injecting it (unless you re-provide it in another module/component's providers array).

For some things, that behavior is desireable. For instance if you have a user service that provides data about the currently signed in user, that would most likely be a service that's being used everywhere that only needs one instance created. So in that case, providedIn: 'root' or providing it in AppModule makes sense.

On the contrary, if you have a service that provides table data for a table component, then you would probably want that provided at the component level so that every individual instance of a table has access to its own data. If you provided this service at root, then every table would share the same data.

Usually what I do is either just provide the service in a component/module where it's needed or do providedIn: 'root' if it needs to be singleton across the entire app.

You can also create small "atomic" modules where the module provides one service and then import that small module everywhere it's needed in order to allow for lazy loading.

For example:

@NgModule({
    providers: [TestService]
})
export class TestModule { }

Then any module that has a component/directive/service/etc that needs to inject that service you would add TestModule to the imports array of the module that includes that component/directive/service/etc.

constructor(private testService: TestService) { }
@NgModule({
    imports: [TestModule]
})
export class ModuleWithComponentThatNeedsTestService { }

Another thought I had, would be to define a generic service for whatever web api my component is interacting with. Like it is done in react, with hooks and useContext:

useFirestore.js
useStorage.js
useAnalytics.js

I'm not sure if this is a good since most angular src code ive seen other people write has services that are always specific to the database collection or document they are accessing. I am considering now, whether this is a good idea. The drawback is that this is going to be one huge service thats called everywhere in my app, which is certainly unappealing.

export class FirestoreService {

  collection : AngularFirestoreCollection<any>;

  constructor(
    collectionName : string,
    collectionMetadata : { },
    private afs : AngularFirestore
   ) {
      this.collection = this.afs.collection(collection_name)

 }

  create( new_object : { }) { }
  update( new_object: {} ) { }
  delete( ) { } 
  filter,
  search,
  etc...
  
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM