I'm trying to provide a resolve service via the new providedIn
attribute.
This is a translations resolver which I use in a protected module:
import { Injectable } from '@angular/core'; import { Observable , pipe } from 'rxjs'; import {map} from "rxjs/operators"; //This is causing: "WARNING in Circular dependency detected:" import {ProtectedModule} from "../../../protected/protected.module"; import { HttpHandlerService } from '../../http/http-handler.service'; @Injectable({ providedIn: ProtectedModule //Over here (I need the import for this line) }) export class TranslationsResolverService { constructor(private _httpHandlerService : HttpHandlerService) { } resolve(): any { //Do Something... } }
I declared the translations resolver service in the protected routing module:
import { NgModule } from '@angular/core'; import {RouterModule, Routes} from '@angular/router'; import {AuthGuard} from "../core/resolvers/auth/auth.guard"; import {TranslationsResolverService} from "./../core/resolvers/translations/translations-resolver.service"; const routes: Routes = [ { path : 'app' , component: ProtectedComponent, resolve : { translations : TranslationsResolverService // <---- Over here - i can't remove that of course }, canActivate: [AuthGuard], ] } ]; @NgModule({ imports : [RouterModule.forChild(routes)], exports : [RouterModule] }) export class ProtectedRoutingModule { }
Because of the fact that I import (typescript import) the protected.module
in the translations-resolver.service.ts
in order to use it in the providedIn
attribute I get a WARNING in Circular dependency detected:
path/to/translations-resolver.service.ts -> protected/protected.module.ts -> protected/protected-routing.module.ts -> path to translations-resolver.service.ts
The 2nd path (protected/protected.module.ts) is added due to the providedIn
attribute.
I can fix this by just providing the translationsResolver
as a NgModule provider
(in the providers array) but I prefer it to be an injectable
provider.
Any suggestions for solving this?
By default, this decorator has a providedIn property, which creates a provider for the service. In this case, providedIn: 'root' specifies that Angular should provide the service in the root injector.
To reduce or eliminate circular dependencies, architects must implement loose component coupling and isolate failures. One approach is to use abstraction to break the dependency chain. To do this, you introduce an abstracted service interface that delivers underlying functionality without direct component coupling.
I ran into the same problem. Turns out the solution is "don't do it", as explained in this thread by one of the Angular guys: https://github.com/angular/angular-cli/issues/10170#issuecomment-380673276
It boils down to services being easier to tree shake when they are provided by the root module, as I gather.
I'm as disappointed as you are.
I've received 5 up-votes now for this answer, so I feel as though I ought to come clean and say that I'm no longer actually following my own advice on this (below)!
Since official (and widely followed) Angular policy is to use providedIn: 'root'
, I decided that on the whole it would be less confusing for other developers if I just stuck with this. So far it hasn't caused me any problems, but the caveats below still remain and I believe it's important to remain aware of this.
I think Angular have made a bit of a mess of the providedIn
syntax. It seems to have confused a lot of people. E.g. see these two github threads:
The providedIn
syntax seems to have 2 main benefits:
providedIn: 'root'
ensures that you only ever get one instance of the serviceBut you only really need (1) if you're writing a library rather than an application (because why would you include a service that you didn't need in your application), and you can avoid multiple service instances (2) just by making sure you don't import the service module more than once.
The problems with the providedIn
syntax are:
providedIn: 'root'
breaks the link between the service and the module it "lives in" (or "with") - because the service doesn't know about the module and the module doesn't know about the service. This means the service no longer really "belongs" to that module, and will just get bundled with whatever references it. This in turn means that it is now up to the service consumer to make sure the service's injectable dependencies (if it has any) are available before it is used, which is confusing and quite counter-intuitive (unless of course the dependencies - and their dependencies etc. - are also all providedIn: 'root'
, in which case they will take care of themselves).This is contrary to official Angular guidance, but my advice would be: Don't use providedIn
, unless you are writing a third party library which requires tree-shaking - use the old (not deprecated) providers
syntax on the module instead, i.e.:
@NgModule({ providers: [MyService], })
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With