The ‘controller ngModel required by directive’ error can be confusing when you first come across it, particularly if you get it when running your unit tests. But it’s a simple fix, and obvious when you understand what Angular’s trying to do.

Tl;dr

This error is caused by a directive with require: '^ngModel' in its definition object, and no ngModel attribute in the HTML used to compile the directive (either in your app or your tests).

Fixing the Problem

The AngularJS error:

Controller 'ngModel' required by directive

is thrown because your directive has the following property on its directive definition object (DDO):

require: '^ngModel'

…and you haven’t added an ng-model="somePropertyName" attribute onto the directive’s declaration in its HTML.

To fix it, simply add ng-model as an attribute to the HTML used to compile the directive, like so:

<myDirective ngModel="someProperty"></myDirective>

Eh?!

In Plain(er) English

Suppose you have the following directive:

angular
   .module('myApp')
   .directive('myDirective', myDirective);

function myDirective(){

    var directiveDefinitionObject = {
        templateUrl: '/partial.html',
        controller: 'myDirectiveCtrl',
        restrict: 'E',
        require:'ngModel',
        scope: {}
   }
}

Note the line require ngModel. This tells Angular that myDirective must have the controller used by ngModel.

When Angular sees this statement, it will do the following:

  • look for the ngModel directive (which is a core directive)
  • access ngModel‘s controller (called ngModelController)
  • pass ngModel‘s controller to myDirective‘s link function

Once this is done, ngModel‘s controller (i.e. ngModelController is available to use in the link function via the function’s controller argument:

link: function(scope, elem, attrs, controller){
   // Angular has found ngModelController, and has passed it into the 
   // link function as the controller argument.
}

You’re happy, as you can use ngModelController‘s properties and functions, and Angular’s happy, as it’s found what you told it to find.

But where does Angular find ngModel? You need to tell it where it is by defining it explicitly as an attribute in myDirective‘s HTML:

<myDirective ngModel="someProperty"></myDirective>

You also need to ensure it’s in the HTML fragment you use to compile the directive in its unit tests:

var compiledDirective = $compile(angular.element(
<myDirective ngModel="someProperty"></myDirective>
))(scope);

There are no comments.

Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>