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

Commit 8965d57

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 951a274 commit 8965d57

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
@@ -6267,6 +6267,89 @@ describe('$compile', function() {
62676267
});
62686268
});
62696269

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

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

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

0 commit comments

Comments
 (0)