Home > Enterprise >  How to Create a Module Scoped Service without Circular Dependencies?
How to Create a Module Scoped Service without Circular Dependencies?

Time:02-26

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: enter image description here

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) with providedIn 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 of XYZService will be shared in that module. So, any component in that module can inject XYZService without any circular dependency error.

  • Case 2: The XYZModule is imported by AppModule, In this case, your service instance will be shared throughout the application. Even with any lazy loaded module.

  • Case 3: The XYZModule is imported by AppModule & Module2 individually. In this case, Module2 will create its own instance of XYZService. All components declared inside Module2 will not share AppModule's instance of XYZService

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

  • Related