Tips for preventing the occurrence of a "cycle dependency" error in the scenario where a service is requiring the importation of another service

In my Angular front-end project, I am working on consolidating all HTTP calls to the back-end within a single service.

The commit causing issues can be found here (with just one change for it to work), and here is a summary of the changes.

I have a class called BackendService:

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, BehaviorSubject } from 'rxjs';
import { catchError, timeout } from 'rxjs/operators';

const backendUrl = 'http://localhost:5001/api/';
const statusEndpoint = '/status';

@Injectable({
  providedIn: 'root'
})
export class BackendService {
  // exposed Subject of this service
  public status$ = new BehaviorSubject<BackendStatus>(defaultStatus);

  constructor(
    private http: HttpClient,
  ) { }

  private updateStatus(): void {
    this.get(statusEndpoint).subscribe(raw => { this.status$.next(raw); });
  }

  public get(endpoint: string): Observable<HttpResponse<any>> {
    return this.http.get(backendUrl + endpoint);
  }

(...)

Now, I aim to utilize the BackendService.get method in other services to handle timeouts, error handling, and similar tasks centrally.

When I inject this service into another service like this:

import { Injectable } from '@angular/core';

import { BackendService } from './backend.service';

@Injectable({
  providedIn: 'root'
})
export class AuthService {

  constructor(
    private backend: BackendService,  // <-- here!
  ) { }

The compilation works without errors, but I encounter the following console error:

ERROR Error: Cannot instantiate cyclic dependency! AuthService
    Angular 7
    UserPanelComponent_Factory user-panel.component.ts:12
    Angular 5
        getNodeInjectable
        instantiateAllDirectives
        createDirectivesInstances
        elementStart
        element
    AppComponent_Template app.component.html:4
    Angular 20
core.js:6241:19

This issue occurs because user-panel.component.ts imports AuthService:

import { Component, OnInit } from '@angular/core';

import { AuthService, Credentials } from '../auth.service';
import { UserService, UserDetails } from '../user.service';


@Component({
  selector: 'app-user-panel',
  templateUrl: './user-panel.component.html',
  styleUrls: ['./user-panel.component.scss']
})
export class UserPanelComponent implements OnInit {
  public userDetails: UserDetails;

  constructor(
    public auth: AuthService,
    public user: UserService,
  ) {}

  ngOnInit(): void {
    // trigger refresh from local storage once the component is ready
    this.auth.initializeFromStorage();
  }

  onLogOut() {
    this.auth.logUserOut();
  }

}

So, how can I resolve this issue of importing a service into another service?

Additional Notes:

  • I have checked similar questions regarding cyclic dependencies, but my case seems isolated with no additional dependencies. I have not come across any relevant solutions online either.

  • I suspect the issue may be related to the implementation of @Injectable, although removing its content did not yield any noticeable improvements.

Answer №1

The common practice involves using an Injector to obtain a reference to a fresh BackendService instance

private backend: BackendService
constructor (injector:Injector) {
    this.backend = injector.get(BackendService);
}

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

Retrieving the initial row of a specified category using ngFor in Angular 2

My challenge involves working with data in Angular 2. Here is a sample dataset: [ {text: "first", name: "a"}, {text: "rw", name: "a"}, {text: "ds", name: "b"}, {text: "asdf", name: " ...

Enhancing Your React Code with Prettier, ESLint, and React

Encountering conflicting rules on TS / React imports as a beginner, while using Eslint / Prettier. I'm getting an error stating 'React' is declared but its value is never read.. However, when I remove it, another error saying 'React&apo ...

Binary string type definition in Typescript

Is there a way to create a type that ensures each character is either '1' or '0' in JavaScript? type Binary = '1'|'0' The current type works for single characters only. Is it possible to create a type for repeating ...

There is no such property - Axios and TypeScript

I am attempting to retrieve data from a Google spreadsheet using axios in Vue3 & TypeScript for the first time. This is my initial experience with Vue3, as opposed to Vue2. Upon running the code, I encountered this error: Property 'items' does ...

Issue with implicitly assigning 'any' type to overloaded variadic generic function

We have some code snippets for you to review: export type actions = { abort: () => void; back: () => void; next: () => void; resume: () => void; }; class Sabar { public use<T1>(fn: (arg1: T1, ctx: object, actions: actions) =&g ...

Inter-class communication using TypeScript callbacks

Struggling with Typescript, I have encountered an issue while trying to send a callback from an angular controller to an angular service. Despite setting a break point at the beginning of the callback function using Chrome Dev Tools, it never gets triggere ...

Tips on preventing state sharing in Angular applications

Delving into the world of Angular has presented me with an intriguing issue. I've crafted a component dedicated to displaying a dialog, complete with its own template (HTML), CSS, and TypeScript files. Whenever a user clicks on an item within a list ...

String nested path TypeScript object type

Check out this get function I've written: function get<T>(obj: T, props: (keyof T)[] | keyof T): any { const toArray = coereceArray(props); return obj && toArray.reduce( (result, prop) => result == null ? undefined : result[p ...

What is the best way to bring in the angular/http module?

Currently, I am creating an application in Visual Studio with the help of gulp and node. Node organizes all dependencies into a folder named node_modules. During the build process, gulp transfers these dependencies to a directory called libs within wwwroo ...

Is it feasible to expand types in Typescript?

Let's consider the scenario with this specific data structure: type Event = { name: string; dateCreated: string; type: string; } Now, I am looking to expand upon this type, for instance, type UserEvent extends Event = { UserId: string; ...

Get the updated value from Firebase after it has been increased

One way I am incrementing a value is by using the following code: const increment = firestore.FieldValue.increment(1); this.fb.afs.collection(colId).doc(docId).set({ invoiceCount: increment }, { merge: true }) I want to retrieve the incremented valu ...

Circular Dependencies in Angular (only the file name)

Previously, I used to keep interfaces and services in separate files but later combined them into one file since they were always requested together. For example, instead of having user.interface.ts and user.service.ts as separate files, I now have all the ...

Managing DOM elements within a Vue 3 template using Typescript

As I delve into the world of Vue 3 as a beginner, I encountered a challenge when it came to managing the DOM within Vue 3 templates. Let's take a look at the source code. MainContainer.vue <template> <div class="main-container" r ...

An array comprising multiple arrays containing strings

I need help creating a nested array of strings like the one shown below: let rules : type = [ ["N"] ["N", "N"] ["N", "N", "N"] ] I'm struggling to set the correct type for this array. Can you assist me with this? ...

A guide to validating a pair of fields within a single object using React hooks and the Yup library

{ label: 'Room', name: 'room', rule: yup.array(yup.object()).required(), renderer: (data: any) => { const { control, register, errors } = useFormContext(); return ( ...

The TypeScript rule in the project-specific .eslintrc.js file is not being applied as expected

Currently, I am following a tutorial on Ionic/Vue 3 which can be found here. However, when I try to serve the project, I encounter the following error: https://i.stack.imgur.com/k4juO.png It appears that my project-level .eslintrc.js file is not being ap ...

The synergy between ternary operators and Vue filters

Recently, I came across a peculiar issue while working with Vue. Take a look at the code snippet from vue.html: <label :text= "$props.information ? (($props.information.primary || $props.information.secondary) | myFilter) : `No info`"> </lab ...

Tips for modifying the size of your input

I'm currently utilizing components from and I'm looking to modify the length of the input box to match the black box seen here: https://i.sstatic.net/RWYTU.png In the image, you can observe that the input box should be equal in length to the b ...

Avoiding tab events in Angular: Tips and Tricks

I am attempting to implement logic using the tab key without actually changing focus. After consulting this answer's comments, I have included both false in my markup and preventDefault() in the method. onKey(event: KeyboardEvent) { event.preventD ...

Are there any code paths that do not result in a return value?

Can anyone provide insights on the error message "Not all code paths return the value" that I'm encountering? Additionally, is there a more efficient way to utilize ES6 features instead of using forEach loops? main.ts if (rxInfos.length && rxInfos ...