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

Commit c0bf481

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 e322cd9 commit c0bf481

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)