btk
btk

Reputation: 3225

"require" DDO option of Angular directive does not throw an error when it should

Forgive me if this is obvious, but I am just learning the ropes.

I've been following this article, trying to understand directives in AngularJS.

The docs specify that the require option of a directive's DDO should throw an error if the referred-to directive is not found.

I cannot seem to make it throw an error - here's my code (I'm using v1.3.13)

test.html:

<body ng-app="Test">
    <dir />
</body>

test.js:

var test = angular.module('Test', []);

test.directive('dir', function() {
    return {
        require: '99 red baloons',
        restrict: 'E',
        template: '<div>this should not work</div'
    };
});

(Here's the corresponding jsfiddle)

Everything seems to work fine, the $compile function doesn't complain, the directive gets picked up and rendered in the DOM just fine. What am I missing?

Thank you!

EDIT

Seems this is a bug in Angular, here's the issue to match

Upvotes: 3

Views: 600

Answers (1)

acg
acg

Reputation: 961

So a couple issues exist here, one is the code and the other (in my opinion) is an incorrect manner by which the angular team has implemented the Require feature, which we need to work around.

For your code to work you will need to reference the required controller in the link function, until you do that it wont check to see if the controller exists in the previous elements and will not throw an exception, the other issue is that you will need to build the required controller in a directive for the linking api's to work.

The angular team has unfortunately has created the default behavior, which I disagree with, that during the compilation/rendering stages of a directive when its determining what is required it will still render the transcluded/template of the directive that has an error. So it looks like its working even though the app is throwing an exception. To get around this you can set a scoped property in the sub directive's link function to true once its done successfully loading, which you will use in an ng-show in the template. If the link never runs because the required controller is not satisfied then the template wont be shown.

Here is a working sample:

<body>
    <div main>
    </div>

    <script type="text/ng-template" id="main.html">
      <span>Hello, {{name}}!</span>
      <button ng-click="mainCtrl.log('Log Log Log, wondeful LOG!!!')">LOG</button>
      <sub></sub>
    </script>

    <script type="text/ng-template" id="sub.html">
      <div ng-show="loaded">{{name}} this should not work</div><div ng-transclude></div>
    </script>
</body>

With the corresponding javascript, just change the required controller to a bogus name to see the error in the console:

var app = angular.module('myApp', []);

app.directive('main', function() {
  return {
    restrict: 'A',
    transclude: true,
    controllerAs: 'mainCtrl',
    controller: function($scope) {
      $scope.name = 'World';
      this.log = function(test) {
        console.log(test);
      };
    },
    templateUrl: 'main.html'
  }
});

app.directive('sub', function() {
  return {
    require: '^main',
    restrict: 'E',
    transclude: true,
    templateUrl: 'sub.html',
    link: function(scope, element, attrs, requiredCtrl) {
      requiredCtrl.log("heck ya!")
      scope.loaded = true;
    }
  };

});

Upvotes: 5

Related Questions