1

I'm having a trouble with my angular project. I'm having these warnings:

WARNING in Circular dependency detected:
src\app\core\http\content.service.ts -> src\app\core\http\domain.service.ts -> 
src\app\shared\http\domain-shared.service.ts -> 
src\app\core\http\content.service.ts

I have 3 services:

Content Service where I get a bunch of codes of my DB with the method

getContentCodes()
  constructor(
    private httpClient: HttpClient,
    private tokenService: TokenService,
    private domainService: DomainService
  ) {
    this.externalToken = new Token();
    this.domainData = this.domainService.getDomainData() as DomainData;
  }

Domain Service where I have the code to get a values from the instance of this or the storage

  constructor(private storageBrowser: StorageBrowser, private domainSharedService: DomainSharedService) {
    this.init();
  }

  getDomainData(): DomainData {
    if (this.domainData && Object.values(this.domainData).length > 0) {
      return this.domainData;
    }

    let domain = this.storageBrowser.get(StorageVariables.DOMAIN_DATA);
    if (!domain) {
       domain = this.checkForDomain();
    }

    this.domainData = new DomainData(domain);
    return this.domainData;
  }

  setDomainDataItem(item: DomainItem) {
    this.domainData.setDomainItem(item);
    this.storageBrowser.set(StorageVariables.DOMAIN_DATA, this.domainData, true);
  }

  async checkForDomain(): Promise<DomainData> {
    return await this.domainSharedService.checkDomainData();
  }

and finally I have the Domain Shared service where I will have make the HTTP request to get the Domain Data values

constructor(private clubService: ClubService, private content: ContentService) {
    this.domainCalls = [];
}

async checkDomainData(): Promise<DomainData> {
    const whiteList: string[] = await this.content.getContentCodes();
    const clubLevels: ClubLevel[] = await this.clubService.getClubLevels();
    this.domainCalls = [{ code: 'clubLevels', value: clubLevels.reverse() }, { code: 'whiteList', value: whiteList}];
    const domainItems: DomainItem[] = this.setItems(this.domainCalls);
    const domainData: DomainData = new DomainData();
    domainData.data = domainItems;
    return domainData;
}

Content uses domain service to get the domain shared values that is checked in the domain service where is injected domain shared service. And in this Domain Shared service is injected Content to use getContentCodes() to get the Whitelist

There is a way that I could make this Services communicate each other without having to Inject them or without having the circular dependency?

Thank you

Sergio
  • 43
  • 10
  • 1
    Circular dependencies are usually a warning of bad design. You should definitely review your architecture, eventually splitting in different classes or services. Names here are too generic to help you. – Massimiliano Sartoretto Mar 13 '19 at 14:31
  • please provide import section of each file, also if you export them with index.ts please provide that one too – Reza Mar 13 '19 at 15:02
  • See related: [How to solve circular dependency?](https://softwareengineering.stackexchange.com/q/306483/244226) and [how to avoid circular dependencies here](https://stackoverflow.com/a/1962292/1260204) – Igor Mar 13 '19 at 15:04
  • @cgTag Having classes depending on each other breaks multiple design principles. Not saying it's not doable, but I would carefully review the design of the classes before tweaking the code to "avoid the issue" – Massimiliano Sartoretto Mar 13 '19 at 15:19
  • @cgTag There is no worse blind man than the one who doesn't want to see. Have a nice and productive day. – Massimiliano Sartoretto Mar 13 '19 at 15:26

1 Answers1

0

You can remove contentService from constructor injection in DomainSharedService, and use it as an argument in checkDomainData, e.g.

async checkDomainData(content: ContentService): Promise<DomainData> {
   const whiteList: string[] = await content.getContentCodes();
   ...
}

To use this service in a component, say, FooComponent,

class FooComponent {
  constructor(private content: ContentService, private domainSharedService: DomainSharedService) {}
  someMethod() {
    this.domainSharedService.checkDomainData(this.content); 
  }
}

Alternatively, you can fetch contentService manually by using angular injector, e.g., in DomainSharedService,

constructor(private injector: Injector, ...) {    }

async checkDomainData(): Promise<DomainData> {
  let content = this.injector.get(ContentService);
  const whiteList: string[] = await content.getContentCodes();
  ...
}

The above workaround can avoid circular dependencies. But as others suggested, it is a bad design :)

ABOS
  • 3,723
  • 3
  • 17
  • 23