angular/angular.js · error · Error
No component found
Error message
No component found
What it means
$componentController(name, locals, bindings, ident) resolves the `<name>Directive` service and filters directive definitions to those that qualify as components: having a controller AND a controllerAs AND restrict === 'E'. Zero candidates means directives exist under that name but none is a component (the name being entirely unregistered fails earlier with an Unknown provider error), so it throws 'No component found'.
Source
Thrown at src/ngMock/angular-mocks.js:2547
* @param {Object=} bindings Properties to add to the controller before invoking the constructor. This is used
* to simulate the `bindToController` feature and simplify certain kinds of tests.
* @param {string=} ident Override the property name to use when attaching the controller to the scope.
* @return {Object} Instance of requested controller.
*/
angular.mock.$ComponentControllerProvider = ['$compileProvider',
function ComponentControllerProvider($compileProvider) {
this.$get = ['$controller','$injector', '$rootScope', function($controller, $injector, $rootScope) {
return function $componentController(componentName, locals, bindings, ident) {
// get all directives associated to the component name
var directives = $injector.get(componentName + 'Directive');
// look for those directives that are components
var candidateDirectives = directives.filter(function(directiveInfo) {
// components have controller, controllerAs and restrict:'E'
return directiveInfo.controller && directiveInfo.controllerAs && directiveInfo.restrict === 'E';
});
// check if valid directives found
if (candidateDirectives.length === 0) {
throw new Error('No component found');
}
if (candidateDirectives.length > 1) {
throw new Error('Too many components found');
}
// get the info of the component
var directiveInfo = candidateDirectives[0];
// create a scope if needed
locals = locals || {};
locals.$scope = locals.$scope || $rootScope.$new(true);
return $controller(directiveInfo.controller, locals, bindings, ident || directiveInfo.controllerAs);
};
}];
}];
/**
* @ngdoc module
* @name ngMockView on GitHub (pinned to d8f77817eb)
Solutions
- Define the test target with .component('name', {...}) — it enforces restrict:'E' and a default controllerAs ('$ctrl'), satisfying all three criteria.
- If it must stay a directive, add controllerAs and restrict:'E' (or at least controller + controllerAs), or instantiate its controller directly with $controller instead of $componentController.
- Make sure the module that declares the component is loaded: beforeEach(module('my.component.module')).
Example fix
// before
angular.module('app').directive('rating', function() {
return {restrict: 'E', template: '...', controller: RatingCtrl}; // no controllerAs
});
$componentController('rating', null, {value: 3}); // throws: No component found
// after
angular.module('app').component('rating', {
template: '...',
bindings: {value: '<'},
controller: RatingCtrl // .component() adds controllerAs '$ctrl', restrict 'E'
});
$componentController('rating', null, {value: 3}); Defensive patterns
Strategy: validation
Validate before calling
// Verify a component-shaped directive exists before creating its controller
inject(function($injector) {
var name = 'rating';
if (!$injector.has(name + 'Directive')) {
throw new Error('No directive named ' + name + ' — is the module loaded?');
}
var isComponent = $injector.get(name + 'Directive').some(function(d) {
return d.controller && d.controllerAs && d.restrict === 'E';
});
if (isComponent) $componentController(name, null, bindings);
}); Type guard
function looksLikeComponent(directiveDef) {
return !!(directiveDef && directiveDef.controller &&
directiveDef.controllerAs && directiveDef.restrict === 'E');
} Prevention
- Register test targets with .component(), which guarantees controllerAs and restrict:'E'.
- Always load the declaring module in beforeEach(module(...)) before $componentController.
- For legacy directives, use $controller directly instead of $componentController.
When it happens
Trigger: The name is registered via .directive() with a controller but no controllerAs (or restrict 'A'); the directive definition object lacks a controller entirely; a component-style directive written by hand missing one of the three criteria; the target is an old-style directive, not a .component().
Common situations: Modernizing a legacy directive codebase and using $componentController on pre-1.5 directives; the component lives in a submodule that was not passed to beforeEach(module(...)) — though a fully missing name throws Unknown provider first; a directive with restrict:'EA' instead of 'E'.
Related errors
- Too many components found
- No deferred tasks to be flushed
- Deferred tasks to flush ({}): {}
- Expected $log to be empty! Either a message was logged unexp
- No pending animations ready to be closed or flushed
AI-assisted analysis of angular/angular.js@d8f77817eb (2026-08-21).
Data as JSON: /api/errors/125cfa00bad7fd97.
Report an issue: GitHub.