Optional nested directive controllers
The AngularJS construct that allows you to build channels of communication between directive siblings or parents in the same DOM ancestry also allows you to optionally require a directive controller of a sibling or parent.
Getting ready
Suppose that your application includes the following:
(index.html) <div ng-app="myApp"> <div parent-directive> <div child-directive sibling-directive> </div> </div> </div> (app.js) angular.module('myApp', []) .directive('parentDirective', function ($log) { return { controller: function () { this.identify = function () { $log.log('Parent!'); }; } }; }) .directive('siblingDirective', function ($log) { return { controller: function () { this.identify = function () { $log.log('Sibling!'); }; } }; });
How to do it…
Note that in index.html
, the missingDirective
is not present. A ?
prefixed to the require
array element denotes an optional controller directive. This is shown in the following code:
(app.js) .directive('childDirective', function ($log) { return { require: [ '^parentDirective', '^siblingDirective', '^?missingDirective' ], link: function (scope, el, attrs, ctrls) { ctrls[0].identify(); // Parent! ctrls[1].identify(); // Sibling! $log.log(ctrls[2]); // null } }; });
Tip
JSFiddle: http://jsfiddle.net/msfrisbie/kr6w2hvb/
If the controller exists, it will be served in the same fashion as the others. If not, the returned array will be a null value at the corresponding index.
How it works…
An AngularJS controller is merely a JavaScript constructor function, and when parentDirective
and siblingDirective
are required, each directive returns their controller object. As you are using the controller object and not the controller scope, you must define your public controller methods on this
instead of $scope
. The $scope
doesn't make sense in the context of a foreign directive—recall that the directive is in the process of being linked when all of this happens.