Circular dependency in DI detected

Recently I met with the error of Circular Dependency. The most simple explanation I have found is located here in https://angular.io/errors/NG0200.

Let us try to understand how circular dependency occurs in the code. and how to fix a circular dependency.

Here I have written a demo code to see the circular dependency and fixes. I have faced two cases of circular dependencies a lot. So, here is the explanation.

home.page.ts

import { Component } from '@angular/core';
import { Service1Service } from '../service1/service1.service';

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})
export class HomePage {

  constructor(private s1: Service1Service) {}

  HomeMethod(){
    console.log("Home Method");
    this.s1.Method1InService1();
  }

}

home.page.html

<ion-header [translucent]="true">
  <ion-toolbar>
    <ion-title>
      Home
    </ion-title>
  </ion-toolbar>
</ion-header>

<ion-content [fullscreen]="true">
  <ion-header collapse="condense">
    <ion-toolbar>
      <ion-title size="large">Home</ion-title>
    </ion-toolbar>
  </ion-header>
  <ion-item>
    Home
    <ion-button (click)="HomeMethod()"> Home Button</ion-button>
  </ion-item>
</ion-content>

service1.service.ts

import { Injectable } from '@angular/core';
import { Service2Service } from '../service2/service2.service';

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

  constructor(private s2: Service2Service) { }

  Method1InService1(){
    console.log(" Method 1 In Service 1");
    this.s2.Method1InService2();
  }
}

service2.service.ts

import { Injectable } from '@angular/core';
import { Service1Service } from '../service1/service1.service';

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

  constructor(private s1: Service1Service) { }

  Method1InService2(){
    console.log(" Method 1 In Service 2");
  }
  Method2InService2(){

  }
}
Circular Dependency between two services:
 
If you have a circular dependency between two services in your code. You will get a warning during compile time. The warning will show your circular dependencies. 
 
 
And if you run the code, you will get the blank page and later inspection gets the below error:
 
Error: NG0200: Circular dependency in DI detected for Service1Service.
 
 
Fix:
Break the circular dependencies.
  1. Find the dependent methods. service1.  HomeMethod() -> Method1InService1() ->Method1InService2()-> Method1InService1()
  2. Remove the method call that is causing circular flow 
 
 
3. Eliminate the import and object of the class.
import { Injectable } from '@angular/core';

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

  constructor() { }

  Method1InService1(){
    console.log(" Method 1 In Service 1");

  }
}
This fixes the error
 

Circular Dependency between service and component/page:

In the case of circular dependency between service and components, the error is not specified as between two services. The error can look like the below. Here our guess goes as to add the provider, but the real issue is the circular dependency. To make it clear, see the warnings below as well. If there is a warning of circular dependency and this error, then circular dependency is causing this error.

ERROR Error: Uncaught (in promise): NullInjectorError: R3InjectorError(HomePageModule)[Service1Service -> Service1Service -> HomePage -> HomePage -> HomePage]:
NullInjectorError: No provider for HomePage!
NullInjectorError: R3InjectorError(HomePageModule)[Service1Service -> Service1Service -> HomePage -> HomePage -> HomePage]:
NullInjectorError: No provider for HomePage!

 

 

Code that causes this condition:

home.page.ts

import { Component } from '@angular/core';
import { Service1Service } from '../service1/service1.service';

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})
export class HomePage {

  constructor(private s1: Service1Service) {}

  HomeMethod(){
    console.log("Home Method");
    this.s1.Method1InService1();
  }

}

service1.service.ts

import { Injectable } from '@angular/core';
import { HomePage } from '../home/home.page';

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

  constructor(private hpage: HomePage) { }

  Method1InService1(){
    console.log(" Method 1 In Service 1");
    this.Method2InService1();
  }

  Method2InService1(){
    console.log(" Method 2 in Service 1 ");
    this.hpage.HomeMethod();
  }
}

Fix:

The steps are the same as between services.

1. Find the dependent methods

HomeMethod() -> Method1InService1() -> Method2InService1() -> HomeMethod()

So breaking the dependency is breaking the flow between Method2InService1() to HomeMethod().

2. eliminate the method call which is causing the dependency and remove the import statement

service1.service.ts

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

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

  constructor() { }

  Method1InService1(){
    console.log(" Method 1 In Service 1");
    this.Method2InService1();
  }

  Method2InService1(){
    console.log(" Method 2 in Service 1 ");
  }
}

home.page.ts

import { Component } from '@angular/core';
import { Service1Service } from '../service1/service1.service';

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})
export class HomePage {

  constructor(private s1: Service1Service) {}

  HomeMethod(){
    console.log("Home Method");
    this.s1.Method1InService1();
    this.s1.Method2InService1();
  }

}

Note: This code is very simple here, but when you have a number of components, services and methods. This error can really take hours of your time. So when you get a warning of "Circular dependency". Do not ignore the warning.

Thank you, Hope this is helpful.

 

 

Add comment