Angular 1.x Directive Definition Object: `require` property


November 25, 2014

As we all know, the DDO (Directive Definition Object) returned by the Angular 1.x directive callback function has a require property, that sort of establishes dependency of one directive on others. This is a convenient way of building components that contain multiple directives where one directive may depend on the functionality of others. In practice, the require property simply tells Angular compiler where a particular directive controller should be search for.

Recently, reviewing AngularJS 1.3 source code, I’ve realized that there were some additional options for the require property besides what I already knew about.

The way directives currently "require" other directives will be obsolete in Angular 2.0 along with many other things. It is my understanding that the preferred way of directive communication will be via Dependency Injection of one directive into another.

Let’s take this trivial example of defining a UI “Tabs” component in Angular via two directives:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
angular.module('components.tabs', [])
.directive('tabset', function() {
  return {
    restrict: 'EA',
    transclude: true,
    scope: {},
    controller: function($scope) {
      // ...
    }
  }
}).directive('tab', function() {
  return {
    restrict: 'EA',
    require: '^tabset'
    link: function (scope, elem, attrs, ctrl) {
      var tabsetController = ctrl;
      // ...
    }
  }
});

What require: '^tabset' line does here is tells Angular compiler that our tab directive “depends” on the tabset directive via controller defined in the tabset directive. When require property is present, Angular attempts to locate this controller object in the search path and then inject it into the tab directive’s link function as the fourth argument (please note, when using require property, both directives share the same instance of the controller). Where exactly Angular searches for this controller object depends on the prefix of the directive name (e.g. ^ in this case) given in the require property value of DDO.

Here is a list of all prefixes supported by the require: property and their corresponding effect on the search path:

Prefix Search path Error raised if controller not found? Example Link function receives as 4th argument
(no prefix) Current DOM element that directive is applied to Yes tabset Controller object, if found.
? Current DOM element that directive is applied to No ?tabset Controller object, if found, `null` otherwise
^ Current DOM element that directive is applied to and its parents Yes ^tabset Controller object, if found.
^^ Parent elements of the DOM element that the directive is applied to Yes ^^tabset Controller object, if found.
?^ Current DOM element that directive is applied to and its parents No ?^tabset
^?tabset
Controller object, if found, `null` otherwise
?^^ Parent elements of the DOM element that the directive is applied to No ?^^tabset
^^?tabset
Controller object, if found, `null` otherwise

As you’ve probably already noticed, the ? in the prefix simply makes the search optional, so the compiler doesn’t throw any errors and the link function simply receives null as the fourth argument, if such controller is not found.

Also, worth noting that if multiple directives are required, the require property of the directive can take an array argument:

1
2
3
4
5
6
7
8
9
10
11
12
// ...
.directive('tabs', function() {
  return {
    restrict: "EA",
    require: ['^tabset', 'ngModel'] // <- this directive depends on tabset and ngModel directives
    link: function (scope, elem, attrs, ctrls) {
      var tabsetController = ctrls[0]
      var ngModelController = ctrls[1];
      // ...
    }
  };
});

In this case, the injected 4th argument in the link function will be an array of controller objects in corresponding order.

for more tips and best practices.


Today my environment was:

  • Angular 1.3.2
  • Mac OS X 10.10.1