Skip to content

Commit b93b2c4

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 angular#4518
1 parent e322cd9 commit b93b2c4

File tree

2 files changed

+53
-8
lines changed

2 files changed

+53
-8
lines changed

src/ng/compile.js

+16-8
Original file line numberDiff line numberDiff line change
@@ -567,7 +567,9 @@ 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 = /(\?)|(\^\^?)/g,
572+
REQUIRE_PREFIX_PRE_REGEXP = /^((\?)|(\^\^?))+/;
571573

572574
// Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
573575
// The assumption is that future DOM event attribute names will begin with
@@ -1564,14 +1566,20 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
15641566

15651567

15661568
function getControllers(directiveName, require, $element, elementControllers) {
1567-
var value, retrievalMethod = 'data', optional = false;
1569+
var value, retrievalMethod = 'data', optional = false, search = $element, prematch, match;
15681570
if (isString(require)) {
1569-
while((value = require.charAt(0)) == '^' || value == '?') {
1570-
require = require.substr(1);
1571-
if (value == '^') {
1572-
retrievalMethod = 'inheritedData';
1571+
if ((prematch = require.match(REQUIRE_PREFIX_PRE_REGEXP)) &&
1572+
(match = prematch[0].match(REQUIRE_PREFIX_REGEXP))) {
1573+
for (var i=0, ii=match.length; i<ii; ++i) {
1574+
value = match[i];
1575+
switch (value) {
1576+
case '^': retrievalMethod = 'inheritedData'; break;
1577+
case '^^': retrievalMethod = 'inheritedData'; search = $element.parent(); break;
1578+
case '?': optional = true; break;
1579+
}
15731580
}
1574-
optional = optional || value == '?';
1581+
1582+
require = require.substring(prematch[0].length);
15751583
}
15761584
value = null;
15771585

@@ -1580,7 +1588,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
15801588
value = value.instance;
15811589
}
15821590
}
1583-
value = value || $element[retrievalMethod]('$' + require + 'Controller');
1591+
value = value || search[retrievalMethod]('$' + require + 'Controller');
15841592

15851593
if (!value && !optional) {
15861594
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)