What does "require" of directive definition object take?

24,600

Solution 1

This particular topic of the documentation is indeed confusing, however as strange as it seems to be it all makes sense.

The key to understand the logic behind this definition is to understand that "directive controller" refers to a directive's controller instance and not a controller factory.

Following the tabs example, when a tabs element is created, a new instance of the TabsController is also created and attached to that specific element data, something like:

tabElement.data('$tabsController', tabsControllerInstance)

The require: '^tabs' on the pane element is basically a request for that specific controller instance (tabsControllerInstance) being used on the parent tabs element.

Solution 2

The require parameter, including its prefixes, is documented on the $compile API reference page.

Require another directive and inject its controller as the fourth argument to the linking function. The require takes a string name (or array of strings) of the directive(s) to pass in. If an array is used, the injected argument will be an array in corresponding order. If no such directive can be found, or if the directive does not have a controller, then an error is raised. The name can be prefixed with:

  • (no prefix) - Locate the required controller on the current element. Throw an error if not found.
  • ? - Attempt to locate the required controller or pass null to the link fn if not found.
  • ^ - Locate the required controller by searching the element and its parents. Throw an error if not found.
  • ^^ - Locate the required controller by searching the element's parents. Throw an error if not found.
  • ?^ - Attempt to locate the required controller by searching the element and its parents or pass null to the link fn if not found.
  • ?^^ - Attempt to locate the required controller by searching the element's parents, or pass null to the link fn if not found.
Share:
24,600
tamakisquare
Author by

tamakisquare

Updated on March 16, 2020

Comments

  • tamakisquare
    tamakisquare over 4 years

    require - Require another controller be passed into current directive linking function. The require takes a name of the directive controller to pass in. If no such controller can be found an error is raised. The name can be prefixed with:

    • ? - Don't raise an error. This makes the require dependency optional.
    • ^ - Look for the controller on parent elements as well.

    Above is the definition from the official docs. The ambiguity here is what exactly is a "directive controller".

    Take the tabs directive from the angularjs-ui bootstrap project, as an example.

    angular.module('ui.bootstrap.tabs', [])
    .controller('TabsController', ['$scope', '$element', function($scope, $element) {
      ... // omitted for simplicity
    }])
    .directive('tabs', function() {
      return {
        restrict: 'EA',
        transclude: true,
        scope: {},
        controller: 'TabsController',
        templateUrl: 'template/tabs/tabs.html',
        replace: true
      };
    })
    .directive('pane', ['$parse', function($parse) {
      return {
        require: '^tabs',
        restrict: 'EA',
        transclude: true,
        scope:{
          heading:'@'
        },
        link: function(scope, element, attrs, tabsCtrl) {
          ... // omitted for simplicity
        },
        templateUrl: 'template/tabs/pane.html',
        replace: true
      };
    }]);
    

    The pane directive has require: '^tabs', in which tabs is the name of a directive on its parent element, while the name of the controller attached to that directive is TabsController. From my own interpretation of the above definition, it should have been require: '^TabsController' not require: '^tabs' and that's obviously wrong. Please tell me what am I missing in my comprehension.

  • tamakisquare
    tamakisquare over 11 years
    Thx bmleite. How did you manage to find out the details on this topic? Did you have other learning resources other than the official docs?
  • Ben Wilde
    Ben Wilde almost 10 years
    Additionally (per docs), you can require multiple by passing an array, and they will come into the link function (4th param) as an array as well.
  • URL87
    URL87 over 9 years
    @BenWilde : Does ?^ make the same as ^? ? Does there is order significance for these prefixes ?
  • Blaise
    Blaise over 9 years
    @URL87 In the current implementation, order does not matter.
  • geoidesic
    geoidesic over 7 years
    Note: My tests seem to indicate that multiple nestings using require will bring back the highest level parent's controller, rather than the immediate parent's controller. Which makes it useless for controlling big families because the grandson will always mistake his grandfather for his father.