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

Commit 0780666

Browse files
committed
feat($compile): support omitting required controller name if same as the local name
Basically, making `require: {someDir: '?^someDir'}` equivalent to `require: {someDir: '?^'}`. Closes #14513
1 parent 6d2e071 commit 0780666

File tree

2 files changed

+125
-2
lines changed

2 files changed

+125
-2
lines changed

src/ng/compile.js

+17-2
Original file line numberDiff line numberDiff line change
@@ -324,8 +324,9 @@
324324
* If the `require` property is an object and `bindToController` is truthy, then the required controllers are
325325
* bound to the controller using the keys of the `require` property. This binding occurs after all the controllers
326326
* have been constructed but before `$onInit` is called.
327+
* If the name of the required controller is the same as the local name (the key), the name can be
328+
* omitted. For example, `{parentDir: '^^'}` is equivalent to `{parentDir: '^^parentDir'}`.
327329
* See the {@link $compileProvider#component} helper for an example of how this can be used.
328-
*
329330
* If no such required directive(s) can be found, or if the directive does not have a controller, then an error is
330331
* raised (unless no link function is specified and the required controllers are not being bound to the directive
331332
* controller, in which case error checking is skipped). The name can be prefixed with:
@@ -954,6 +955,20 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
954955
}
955956
}
956957

958+
function getDirectiveRequire(directive) {
959+
var require = directive.require || (directive.controller && directive.name);
960+
961+
if (!isArray(require) && isObject(require)) {
962+
forEach(require, function(value, key) {
963+
var match = value.match(REQUIRE_PREFIX_REGEXP);
964+
var name = value.substring(match[0].length);
965+
if (!name) require[key] = match[0] + key;
966+
});
967+
}
968+
969+
return require;
970+
}
971+
957972
/**
958973
* @ngdoc method
959974
* @name $compileProvider#directive
@@ -990,7 +1005,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
9901005
directive.priority = directive.priority || 0;
9911006
directive.index = index;
9921007
directive.name = directive.name || name;
993-
directive.require = directive.require || (directive.controller && directive.name);
1008+
directive.require = getDirectiveRequire(directive);
9941009
directive.restrict = directive.restrict || 'EA';
9951010
directive.$$moduleName = directiveFactory.$$moduleName;
9961011
directives.push(directive);

test/ng/compileSpec.js

+108
Original file line numberDiff line numberDiff line change
@@ -6268,6 +6268,89 @@ describe('$compile', function() {
62686268
});
62696269
});
62706270

6271+
it('should use the key if the name of a required controller is omitted', function() {
6272+
function ParentController() { this.name = 'Parent'; }
6273+
function ParentOptController() { this.name = 'ParentOpt'; }
6274+
function ParentOrSiblingController() { this.name = 'ParentOrSibling'; }
6275+
function ParentOrSiblingOptController() { this.name = 'ParentOrSiblingOpt'; }
6276+
function SiblingController() { this.name = 'Sibling'; }
6277+
function SiblingOptController() { this.name = 'SiblingOpt'; }
6278+
6279+
angular.module('my', [])
6280+
.component('me', {
6281+
require: {
6282+
parent: '^^',
6283+
parentOpt: '?^^',
6284+
parentOrSibling1: '^',
6285+
parentOrSiblingOpt1: '?^',
6286+
parentOrSibling2: '^',
6287+
parentOrSiblingOpt2: '?^',
6288+
sibling: '',
6289+
siblingOpt: '?'
6290+
}
6291+
})
6292+
.directive('parent', function() {
6293+
return {controller: ParentController};
6294+
})
6295+
.directive('parentOpt', function() {
6296+
return {controller: ParentOptController};
6297+
})
6298+
.directive('parentOrSibling1', function() {
6299+
return {controller: ParentOrSiblingController};
6300+
})
6301+
.directive('parentOrSiblingOpt1', function() {
6302+
return {controller: ParentOrSiblingOptController};
6303+
})
6304+
.directive('parentOrSibling2', function() {
6305+
return {controller: ParentOrSiblingController};
6306+
})
6307+
.directive('parentOrSiblingOpt2', function() {
6308+
return {controller: ParentOrSiblingOptController};
6309+
})
6310+
.directive('sibling', function() {
6311+
return {controller: SiblingController};
6312+
})
6313+
.directive('siblingOpt', function() {
6314+
return {controller: SiblingOptController};
6315+
});
6316+
6317+
module('my');
6318+
inject(function($compile, $rootScope) {
6319+
var template =
6320+
'<div>' +
6321+
// With optional
6322+
'<parent parent-opt parent-or-sibling-1 parent-or-sibling-opt-1>' +
6323+
'<me parent-or-sibling-2 parent-or-sibling-opt-2 sibling sibling-opt></me>' +
6324+
'</parent>' +
6325+
// Without optional
6326+
'<parent parent-or-sibling-1>' +
6327+
'<me parent-or-sibling-2 sibling></me>' +
6328+
'</parent>' +
6329+
'</div>';
6330+
element = $compile(template)($rootScope);
6331+
6332+
var ctrl1 = element.find('me').eq(0).controller('me');
6333+
expect(ctrl1.parent).toEqual(jasmine.any(ParentController));
6334+
expect(ctrl1.parentOpt).toEqual(jasmine.any(ParentOptController));
6335+
expect(ctrl1.parentOrSibling1).toEqual(jasmine.any(ParentOrSiblingController));
6336+
expect(ctrl1.parentOrSiblingOpt1).toEqual(jasmine.any(ParentOrSiblingOptController));
6337+
expect(ctrl1.parentOrSibling2).toEqual(jasmine.any(ParentOrSiblingController));
6338+
expect(ctrl1.parentOrSiblingOpt2).toEqual(jasmine.any(ParentOrSiblingOptController));
6339+
expect(ctrl1.sibling).toEqual(jasmine.any(SiblingController));
6340+
expect(ctrl1.siblingOpt).toEqual(jasmine.any(SiblingOptController));
6341+
6342+
var ctrl2 = element.find('me').eq(1).controller('me');
6343+
expect(ctrl2.parent).toEqual(jasmine.any(ParentController));
6344+
expect(ctrl2.parentOpt).toBe(null);
6345+
expect(ctrl2.parentOrSibling1).toEqual(jasmine.any(ParentOrSiblingController));
6346+
expect(ctrl2.parentOrSiblingOpt1).toBe(null);
6347+
expect(ctrl2.parentOrSibling2).toEqual(jasmine.any(ParentOrSiblingController));
6348+
expect(ctrl2.parentOrSiblingOpt2).toBe(null);
6349+
expect(ctrl2.sibling).toEqual(jasmine.any(SiblingController));
6350+
expect(ctrl2.siblingOpt).toBe(null);
6351+
});
6352+
});
6353+
62716354

62726355
it('should not bind required controllers if bindToController is falsy', function() {
62736356
var parentController, siblingController;
@@ -6797,6 +6880,31 @@ describe('$compile', function() {
67976880
});
67986881
});
67996882

6883+
it('should support omitting the name of the required controller if it is the same as the key',
6884+
function() {
6885+
module(function() {
6886+
directive('myC1', valueFn({
6887+
controller: function() { this.name = 'c1'; }
6888+
}));
6889+
directive('myC2', valueFn({
6890+
controller: function() { this.name = 'c2'; }
6891+
}));
6892+
directive('dep', function(log) {
6893+
return {
6894+
require: { myC1: '^', myC2: '^' },
6895+
link: function(scope, element, attrs, controllers) {
6896+
log('dep:' + controllers.myC1.name + '-' + controllers.myC2.name);
6897+
}
6898+
};
6899+
});
6900+
});
6901+
inject(function(log, $compile, $rootScope) {
6902+
element = $compile('<div my-c1 my-c2><div dep></div></div>')($rootScope);
6903+
expect(log).toEqual('dep:c1-c2');
6904+
});
6905+
}
6906+
);
6907+
68006908
it('should instantiate the controller just once when template/templateUrl', function() {
68016909
var syncCtrlSpy = jasmine.createSpy('sync controller'),
68026910
asyncCtrlSpy = jasmine.createSpy('async controller');

0 commit comments

Comments
 (0)