Angular's trio of services tied in a circle of dependency

I'm encountering an issue with my angular project. These warnings keep popping up:

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 three services:

Content Service where I retrieve codes from my database using 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 fetch values either from the instance or 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 lastly, the Domain Shared service is responsible for making HTTP requests to retrieve 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;
}

The Content service utilizes the domain service to access the domain shared values which are verified in the domain service where the domain shared service is injected. The Domain Shared service then uses the Content service to obtain the Whitelist through getContentCodes()

Is there a way for these services to communicate with each other without having to inject them or avoid the circular dependency?

Thank you

Answer №1

You have the option to remove contentService from the constructor injection in DomainSharedService and instead use it as an argument in checkDomainData.

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

If you need to utilize this service in a component like FooComponent,

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

Another approach is to manually fetch contentService using angular injector, for example, within DomainSharedService:

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

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

This workaround can help avoid circular dependencies. However, as others have pointed out, it may not be the best design choice :)

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Ways to retrieve element values within Angular

Here is an example of an element: <li class="someClass">value1<span>value2</span></li> This list element is created using vanilla JavaScript, and a click event is bound to it as demonstrated below: const list = Array.from(documen ...

"Experiencing issues retrieving user-modified values in NativeScript's TimePicker component

I'm having trouble retrieving the user-modified value from a TimePicker. Instead of getting the modified value, I keep receiving the original value that was initially set in the control. Below is my component template: <TabView [(ngModel)]="tabSe ...

Is Jasmine brushing off TypeScript test files?

I'm diving into my first project with Jasmine, and despite following a tutorial, I'm encountering some hurdles right from the start. After installing jasmine-node, typings, and typescript, I executed: typings install dt~jasmine --save-dev --glo ...

Strategies for persisting data in React using local storage to ensure information is retained after page refresh

I am attempting to store searched recipes data in local storage so that when the user refreshes, the data from the last searched recipe will still be available. I have tried saving the recipes data to local storage when a new search request is made and se ...

Angular 4 incorporating a customized Bootstrap 4 accordion menu for seamless navigation

I am trying to implement a nested menu using a JSON object in Angular 4. Below is the code I have written. <div id="panel-group"> <div class="panel panel-default" *ngFor="let mainItem of objectKeys(my_menu); let i = index"> <div class ...

The distinction between <Type>function and function name():Type in TypeScript is essential to understand the various ways

function retrieveCounter(): Counter { let counter = <Counter>function (start: number) { }; counter.interval = 123; return counter; } Upon inspection of line 2 in the code snippet above, I am left wondering why I am unable to use function ...

Issues arise with PrimeNG multiselect onItemClick functionality following an update to version 7

I am currently working with a MultiSelectComponent that extends the primeng MultiSelect functionality. Recently, I updated from version 6.1.6 to 7.0.4. <ul class="not-important" <li *ngFor="let option of options; let i = index" class="not-import ...

I am unable to utilize the outcome of a custom hook within a function or within an effect hook

I've developed a unique custom hook that retrieves a list of individuals File: persons.hooks.ts import {useEffect, useState} from "react"; import Person from "../../models/person/Person"; const usePersons = () => { const ...

An effective approach to positioning HTML elements at specific X and Y coordinates

I have an innovative project idea! The concept is to enable users to create points by clicking on the display. They can then connect these points by clicking again. However, I am facing a challenge when it comes to creating HTML elements at the exact loc ...

Typescript fails to identify the parameter type of callbacks

I am facing a challenge with the function below and its callback type: type Callbacks = { onSuccess: (a: string) => void; }; function myFunction(event: string, ...args: [...any, Callbacks]) { } The function works correctly except for one issue - ...

An issue occurred in resolving dependencies for the UsersService in Nest

I've been experimenting with Nest a bit, attempting to create a module that I can publish on my private repository for reuse in future projects. However, I've run into an error: ERROR [ExceptionHandler] Nest can't resolve dependencies of the ...

What is the best way to effectively use combinedLatestWith?

https://stackblitz.com/edit/angular-ivy-s2ujmr?file=src/app/country-card/country-card.component.html I am currently working on implementing a search bar in Angular that filters the "countries$" Observable based on user input. My approach involves creatin ...

The argument of type 'NextRouter' cannot be assigned to the parameter of type 'Props' in this scenario

In my component, I am initializing a Formik form by calling a function and passing the next/router object. This is how it looks: export default function Reset() { const router = useRouter(); const formik = useFormik(RecoverForm(router)); return ( ...

Obtain the query response time/duration using react-query

Currently utilizing the useQuery function from react-query. I am interested in determining the duration between when the query was initiated and when it successfully completed. I have been unable to identify this information using the return type or para ...

Eliminating Body Tag Margin in Angular 4: A Step-by-Step Guide

In the Angular 4 project, the app.component.html file does not include a body tag that can be styled to eliminate the padding associated with the body tag. https://i.sstatic.net/5QS9x.jpg An attempt was made in the app.component.css file to remove the ma ...

Display JSON data in a table format using Angular

I have received a JSON result that looks like this: { "discipline":"ACLS", "course": [ { "value":"ACLS Initial", "classes":"0", "students":"0" }, { "BLS":"CPR Inst ...

Typescript is unable to access the global variables of Node.js

After using Typescript 1.8 with typings, I made the decision to upgrade to typescript 2.8 with @types. When I downloaded @types/node, my console started showing errors: error TS2304: Cannot find name 'require'. The project structure is as foll ...

Troubleshooting the Angular CLI issue: Module 'ansi-colors' not found

Having issues with my angular project, despite installing the latest version of NodeJs and NPM. When I try to run my project using the ng command, I encounter the following error message: Error: Cannot find module 'ansi-colors' Require stack: - ...

Setting up data in Firebase can be challenging due to its complex structure definition

https://i.stack.imgur.com/iclx7.png UPDATE: In my firebase structure, I have made edits to the users collection by adding a special list called ListaFavorite. This list will contain all the favorite items that users add during their session. The issue I a ...

How can you incorporate a module for typings without including it in the final webpack bundle?

As I venture into the realm of Webpack, I am faced with the challenge of transitioning from TypeScript 1.x to TypeScript 2. In my previous projects, I typically worked with TypeScript in one module using separate files, TSD for typings, and compiling throu ...