[$injector:cdep] Circular dependency detected

Loading

The [$injector:cdep] Circular Dependency Detected error in AngularJS occurs when two or more components (services, factories, or providers) depend on each other in a loop. This leads to an infinite dependency injection loop, causing AngularJS to throw this error.


1. Understanding Circular Dependency in AngularJS

Error Message in Console:

Error: [$injector:cdep] Circular dependency found: serviceA <- serviceB <- serviceA

What This Means:

  • serviceA depends on serviceB, but serviceB also depends on serviceA.
  • This creates a loop (A → B → A), and AngularJS cannot resolve the dependencies.

2. Common Causes & Fixes

1. Direct Circular Dependency Between Two Services

Issue:
If two services inject each other, AngularJS cannot resolve the dependencies.

Incorrect Code (Circular Dependency Loop)

angular.module('myApp', [])
.service('serviceA', function(serviceB) { // serviceA depends on serviceB
this.getMessage = function() {
return serviceB.getMessage();
};
})
.service('serviceB', function(serviceA) { // serviceB depends on serviceA
this.getMessage = function() {
return "Message from B";
};
});

Fix: Use a third-party mediator service or defer execution.

Solution 1: Use a Third Service (Mediator Pattern)

angular.module('myApp', [])
.service('serviceMediator', function() {
this.getMessage = function() {
return "Message from Mediator";
};
})
.service('serviceA', function(serviceMediator) {
this.getMessage = function() {
return serviceMediator.getMessage();
};
})
.service('serviceB', function(serviceMediator) {
this.getMessage = function() {
return serviceMediator.getMessage();
};
});

Solution 2: Use $injector for Lazy Injection

angular.module('myApp', [])
.service('serviceA', function($injector) {
this.getMessage = function() {
var serviceB = $injector.get('serviceB'); // Lazy injection
return serviceB.getMessage();
};
})
.service('serviceB', function() {
this.getMessage = function() {
return "Message from B";
};
});

Why $injector.get() Works?

  • $injector.get() delays the dependency resolution until it’s actually needed.
  • This breaks the loop because AngularJS doesn’t resolve serviceB immediately.

2. Circular Dependency in Factories

Issue:
Factories can also create circular dependencies if they depend on each other directly.

Incorrect Code:

angular.module('myApp', [])
.factory('factoryA', function(factoryB) {
return {
getData: function() {
return factoryB.getData();
}
};
})
.factory('factoryB', function(factoryA) {
return {
getData: function() {
return "Data from B";
}
};
});

Fix: Use a third-party service or defer execution with $injector (as shown in services).

Solution 1: Refactor with a Mediator Service

angular.module('myApp', [])
.factory('commonService', function() {
return {
getData: function() {
return "Common Data";
}
};
})
.factory('factoryA', function(commonService) {
return {
getData: function() {
return commonService.getData();
}
};
})
.factory('factoryB', function(commonService) {
return {
getData: function() {
return commonService.getData();
}
};
});

3. Circular Dependency in Controllers

Issue:

  • If two controllers depend on each other (e.g., by using ng-controller inside another ng-controller), this can cause circular references.

Incorrect Code:

<div ng-controller="ControllerA">
<div ng-controller="ControllerB"></div>
</div>
angular.module('myApp', [])
.controller('ControllerA', function($scope, ControllerB) { // Circular reference
$scope.message = ControllerB.getMessage();
})
.controller('ControllerB', function($scope, ControllerA) { // Circular reference
$scope.message = "Hello from B";
});

Fix: Avoid direct controller-to-controller dependencies. Instead, use a shared service.

Solution: Use a Shared Service

angular.module('myApp', [])
.service('sharedService', function() {
this.getMessage = function() {
return "Shared Service Message";
};
})
.controller('ControllerA', function($scope, sharedService) {
$scope.message = sharedService.getMessage();
})
.controller('ControllerB', function($scope, sharedService) {
$scope.message = sharedService.getMessage();
});

4. Circular Dependency in Directives

Issue:
If two directives depend on each other, they can create a circular dependency.

Incorrect Code:

angular.module('myApp', [])
.directive('directiveA', function(directiveB) { // Circular reference
return {
template: "<div>Directive A</div>"
};
})
.directive('directiveB', function(directiveA) { // Circular reference
return {
template: "<div>Directive B</div>"
};
});

Fix: Avoid direct directive-to-directive dependencies. Instead, use a common service.

Solution: Use a Shared Service

angular.module('myApp', [])
.service('directiveService', function() {
this.getMessage = function() {
return "Shared Message";
};
})
.directive('directiveA', function(directiveService) {
return {
template: "<div>{{message}}</div>",
controller: function($scope) {
$scope.message = directiveService.getMessage();
}
};
})
.directive('directiveB', function(directiveService) {
return {
template: "<div>{{message}}</div>",
controller: function($scope) {
$scope.message = directiveService.getMessage();
}
};
});

3. Debugging Circular Dependencies

🔎 Steps to Debug in Chrome DevTools

  1. Check Console Errors → Open Developer Tools (F12) → Look for [$injector:cdep] errors.
  2. Use AngularJS Dependency Tree Check
    Run this in the console: angular.module('myApp')._invokeQueue
    • This lists all services, factories, and directives.
    • If a dependency is listed twice, it might be part of a circular loop.
  3. Use $injector.annotate() to Check Dependencies angular.injector(['myApp']).annotate(function(myService) {});
    • If this throws an error, myService is part of a circular dependency.

Leave a Reply

Your email address will not be published. Required fields are marked *