15
votes

What's going on here?

Here are my directives:

// template <input ng-model="theModel"  />
app.directive('bseInput', function () {
    return {
        templateUrl: "/Scripts/bse/bse-inputs.html",
        scope:
        {
            theModel: '=',
        },
        compile: function compile(tElement, tAttrs, transclude) {

            // do stuff

        }
    };
});


app.directive('submitRequired', function (objSvc) {
    return {
        require: 'ngModel',
        link: function (scope, elm, attrs, ctrl) {

          // do something
        }
    };
});

Here is an example of the directive in use:

<input bse-input submit-required="true" the-model="someModel"></input>

Here is the actual error text:

Error: [$compile:ctreq] Controller 'ngModel', required by directive 'submitRequired', can't be found! http://errors.angularjs.org/1.2.2/$compile/ctreq?p0=ngModel&p1=submitRequired at http://www.domain.ca/Scripts/angular/angular.js:78:12 at getControllers (http://www.domain.ca/Scripts/angular/angular.js:5972:19) at nodeLinkFn (http://www.domain.ca/Scripts/angular/angular.js:6139:35) at compositeLinkFn (http://www.domain.ca/Scripts/angular/angular.js:5550:15) at nodeLinkFn (http://www.domain.ca/Scripts/angular/angular.js:6132:24) at compositeLinkFn (http://www.domain.ca/Scripts/angular/angular.js:5550:15) at publicLinkFn (http://www.domain.ca/Scripts/angular/angular.js:5458:30) at http://www.domain.ca/Scripts/angular/angular.js:1299:27 at Scope.$get.Scope.$eval (http://www.domain.ca/Scripts/angular/angular.js:11634:28) at Scope.$get.Scope.$apply (http://www.domain.ca/Scripts/angular/angular.js:11734:23) angular.js:9159 (anonymous function) angular.js:9159 $get angular.js:6751 nodeLinkFn angular.js:6141 compositeLinkFn angular.js:5550 nodeLinkFn angular.js:6132 compositeLinkFn angular.js:5550 publicLinkFn angular.js:5458 (anonymous function) angular.js:1299 $get.Scope.$eval angular.js:11634 $get.Scope.$apply angular.js:11734 (anonymous function) angular.js:1297 invoke angular.js:3633 doBootstrap angular.js:1295 bootstrap angular.js:1309 angularInit angular.js:1258 (anonymous function) angular.js:20210 trigger angular.js:2315 (anonymous function) angular.js:2579 forEach angular.js:300 eventHandler angular.js:2578ar.js:7874

1

1 Answers

22
votes

Just in case, that the above <input> snippet does not contain a typo, this is the issue:

the-model

we need ng-model

<input bse-input submit-required="true" ng-model="someModel.Property"></input>

angular is using normalized/denormalized naming conventions, which at the end means: ng-model is the html way how to express the ngModel. HTML is case insensitive... and this solves this issue

Suggestion. If we are working with multiple directives applied to one element:

  • bse-input
  • submit-required

We should let both of them to work with a standard INPUT settings. So, both should could require ng-model, as a way how to access the model passed to input.

if the-model should be representing different setting, which is absolutely ok, we just do not have to skip passing the ng-model as well

About require:

When you have nested directives that need to communicate with each other, the way to do this is through a controller.

Other directives can have this controller passed to them with the require property syntax. The full form of require looks like:

require: '^?directiveName'

Explanations of the require string:

  • directiveName: This camel-cased name specifies which directive the controller should come from. So if our directive needs to find a controller on its parent , we’d write it as myMenu.
  • ^ By default, Angular gets the controller from the named directive on the same element. Adding this optional ^ symbol says to also walk up the DOM tree to find the directive. For the example, we’d need to add this symbol; the final string would be \^myMenu.
  • ? If the required controller is not found, Angular will throw an exception to tell you about the problem. Adding a ? symbol to the string says that this controller is optional and that an exception shouldn’t be thrown if not found. Though it sounds unlikely, if we wanted to let s be used without a container, we could add this for a final require string of ?\^myMenu.