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 ngMock

View on GitHub (pinned to d8f77817eb)

Solutions

  1. Define the test target with .component('name', {...}) — it enforces restrict:'E' and a default controllerAs ('$ctrl'), satisfying all three criteria.
  2. 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.
  3. 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

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


AI-assisted analysis of angular/angular.js@d8f77817eb (2026-08-21). Data as JSON: /api/errors/125cfa00bad7fd97. Report an issue: GitHub.