Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 65bcd6d

Browse files
Caitlin Pottercaitp
Caitlin Potter
authored andcommitted
feat($compile): optionally get controllers from ancestors only
Implement option to strengthen require '^' operator, by adding another '^'. When a second '^' is used, the controller will only search parent nodes for the matching controller, and will throw or return null if not found, depending on whether or not the requirement is optional. Closes #4518
1 parent 6639ca9 commit 65bcd6d

File tree

2 files changed

+58
-8
lines changed

2 files changed

+58
-8
lines changed

src/ng/compile.js

+21-8
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
567567
Suffix = 'Directive',
568568
COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w_\-]+)\s+(.*)$/,
569569
CLASS_DIRECTIVE_REGEXP = /(([\d\w_\-]+)(?:\:([^;]+))?;?)/,
570-
ALL_OR_NOTHING_ATTRS = makeMap('ngSrc,ngSrcset,src,srcset');
570+
ALL_OR_NOTHING_ATTRS = makeMap('ngSrc,ngSrcset,src,srcset'),
571+
REQUIRE_PREFIX_REGEXP = /^(?:(\^\^?)?(\?)?(\^\^?)?)?/;
571572

572573
// Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
573574
// The assumption is that future DOM event attribute names will begin with
@@ -1565,22 +1566,34 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
15651566

15661567
function getControllers(directiveName, require, $element, elementControllers) {
15671568
var value, retrievalMethod = 'data', optional = false;
1569+
var $searchElement = $element;
1570+
var match;
15681571
if (isString(require)) {
1569-
while((value = require.charAt(0)) == '^' || value == '?') {
1570-
require = require.substr(1);
1571-
if (value == '^') {
1572-
retrievalMethod = 'inheritedData';
1573-
}
1574-
optional = optional || value == '?';
1572+
match = require.match(REQUIRE_PREFIX_REGEXP);
1573+
require = require.substring(match[0].length);
1574+
1575+
if (match[3]) {
1576+
if (match[1]) match[3] = null;
1577+
else match[1] = match[3];
1578+
}
1579+
if (match[1] === '^') {
1580+
retrievalMethod = 'inheritedData';
1581+
} else if (match[1] === '^^') {
1582+
retrievalMethod = 'inheritedData';
1583+
$searchElement = $element.parent();
15751584
}
1585+
if (match[2] === '?') {
1586+
optional = true;
1587+
}
1588+
15761589
value = null;
15771590

15781591
if (elementControllers && retrievalMethod === 'data') {
15791592
if (value = elementControllers[require]) {
15801593
value = value.instance;
15811594
}
15821595
}
1583-
value = value || $element[retrievalMethod]('$' + require + 'Controller');
1596+
value = value || $searchElement[retrievalMethod]('$' + require + 'Controller');
15841597

15851598
if (!value && !optional) {
15861599
throw $compileMinErr('ctreq',

test/ng/compileSpec.js

+37
Original file line numberDiff line numberDiff line change
@@ -3635,6 +3635,43 @@ describe('$compile', function() {
36353635
});
36363636

36373637

3638+
it('should get required parent controller', function() {
3639+
module(function() {
3640+
directive('nested', function(log) {
3641+
return {
3642+
require: '^^?nested',
3643+
controller: function($scope) {},
3644+
link: function(scope, element, attrs, controller) {
3645+
log(!!controller);
3646+
}
3647+
};
3648+
});
3649+
});
3650+
inject(function(log, $compile, $rootScope) {
3651+
element = $compile('<div nested><div nested></div></div>')($rootScope);
3652+
expect(log).toEqual('true; false');
3653+
});
3654+
});
3655+
3656+
3657+
it('should throw if required parent is not found', function() {
3658+
module(function() {
3659+
directive('nested', function() {
3660+
return {
3661+
require: '^^nested',
3662+
controller: function($scope) {},
3663+
link: function(scope, element, attrs, controller) {}
3664+
};
3665+
});
3666+
});
3667+
inject(function($compile, $rootScope) {
3668+
expect(function() {
3669+
element = $compile('<div nested></div>')($rootScope);
3670+
}).toThrowMinErr('$compile', 'ctreq', "Controller 'nested', required by directive 'nested', can't be found!");
3671+
});
3672+
});
3673+
3674+
36383675
it('should get required controller via linkingFn (template)', function() {
36393676
module(function() {
36403677
directive('dirA', function() {

0 commit comments

Comments
 (0)