EDIT: This has now been fixed thanks to the accepted answer, the stackblitz now contains working code
First of all I know its not recommended to create module scoped services, I just want to know if it is possible to do.
I have created a module, service and component. The code is below.
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Fm5Component } from './fm5/fm5.component';
@NgModule({
declarations: [
Fm5Component
],
imports: [
CommonModule
]
})
export class FeatureModule5Module { }
import { Component, OnInit } from '@angular/core';
import { Fm5Service } from '../fm5.service';
@Component({
selector: 'app-fm5',
templateUrl: './fm5.component.html',
styleUrls: ['./fm5.component.scss']
})
export class Fm5Component implements OnInit {
constructor(private fm5Service: Fm5Service) { }
ngOnInit(): void {
this.fm5Service.saySomething();
}
}
import { Injectable } from '@angular/core';
import { FeatureModule5Module } from './feature-module5.module';
@Injectable({
providedIn: FeatureModule5Module
})
export class Fm5Service {
constructor() { }
saySomething(){
console.log("something");
}
}
However when I try to run this I get a circular dependency error. Is it possible to fix this somehow?
I see that this question comes up quite a bit on here in various forms but I'm still none the wiser as to if it can be done.
I've created a stackblitz replicating the error:
CodePudding user response:
Its a known issue with Angular/Typescript. Check out this thread: https://github.com/angular/angular-cli/issues/10170#issuecomment-415758304
Generally, you should use
providedIn
property to limit it to a non-root module, when you are creating a thrid-party library. Because this feature was introduced for allowing tree shakeable services.
- In an application, you will write a service only if you intend to consume it. But in a library, a consumer may or may not consume it. Therefore, it requires tree-shaking.
This is the Circular Dependency that is currently created:
service--[provides itself to]-->module--[declares]-->component--[depends on]-->service
.
This prevents the bundler from tree-shaking it. Therefore Angular warns you about using this pattern with a Circular Dependency error.
Understanding providers scope & providedIn
: XYZModule
.
When you specify scope of a service(
XYZService
) withprovidedIn
to a particular module, you are telling Angular -> Hey Angular, please limit this service instance to the specified module.Case 1: The
XYZModule
is imported by another module(s). In this case, the single instance ofXYZService
will be shared in that module. So, any component in that module can injectXYZService
without any circular dependency error.Case 2: The
XYZModule
is imported byAppModule
, In this case, your service instance will be shared throughout the application. Even with any lazy loaded module.Case 3: The
XYZModule
is imported byAppModule
&Module2
individually. In this case,Module2
will create its own instance ofXYZService
. All components declared insideModule2
will not shareAppModule
's instance ofXYZService
I have created the scenario in this stackblitz
Use the providers
array in the @NgModule
to limit the scope of a service to that module when creating an application.
@NgModule({
declarations: [
Fm5Component
],
imports: [
CommonModule
],
providers:[Fm5Service]
})
export class FeatureModule5Module { }
Still, if you want to use providedIn
syntax, check this visual to understand the problem & its solution using a new Module: https://github.com/angular/angular-cli/issues/10170#issuecomment-414270051