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

Commit 16dccea

Browse files
thorn0gkalpak
authored andcommitted
fix($compile): bindToController should work without controllerAs
Fixes #15088 Closes #15110
1 parent a1bdffa commit 16dccea

File tree

3 files changed

+106
-230
lines changed

3 files changed

+106
-230
lines changed

docs/content/error/$compile/noident.ngdoc

-71
This file was deleted.

src/ng/compile.js

+8-20
Original file line numberDiff line numberDiff line change
@@ -361,9 +361,7 @@
361361
*
362362
* #### `bindToController`
363363
* This property is used to bind scope properties directly to the controller. It can be either
364-
* `true` or an object hash with the same format as the `scope` property. Additionally, a controller
365-
* alias must be set, either by using `controllerAs: 'myAlias'` or by specifying the alias in the controller
366-
* definition: `controller: 'myCtrl as myAlias'`.
364+
* `true` or an object hash with the same format as the `scope` property.
367365
*
368366
* When an isolate scope is used for a directive (see above), `bindToController: true` will
369367
* allow a component to have its properties bound to the controller, rather than to scope.
@@ -1028,20 +1026,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
10281026
bindings.bindToController =
10291027
parseIsolateBindings(directive.bindToController, directiveName, true);
10301028
}
1031-
if (isObject(bindings.bindToController)) {
1032-
var controller = directive.controller;
1033-
var controllerAs = directive.controllerAs;
1034-
if (!controller) {
1035-
// There is no controller, there may or may not be a controllerAs property
1036-
throw $compileMinErr('noctrl',
1037-
'Cannot bind to controller without directive \'{0}\'s controller.',
1038-
directiveName);
1039-
} else if (!identifierForController(controller, controllerAs)) {
1040-
// There is a controller, but no identifier or controllerAs property
1041-
throw $compileMinErr('noident',
1042-
'Cannot bind to controller without identifier for directive \'{0}\'.',
1043-
directiveName);
1044-
}
1029+
if (bindings.bindToController && !directive.controller) {
1030+
// There is no controller
1031+
throw $compileMinErr('noctrl',
1032+
'Cannot bind to controller without directive \'{0}\'s controller.',
1033+
directiveName);
10451034
}
10461035
return bindings;
10471036
}
@@ -2710,7 +2699,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
27102699
var bindings = controllerDirective.$$bindings.bindToController;
27112700

27122701
if (preAssignBindingsEnabled) {
2713-
if (controller.identifier && bindings) {
2702+
if (bindings) {
27142703
controller.bindingInfo =
27152704
initializeDirectiveBindings(controllerScope, attrs, controller.instance, bindings, controllerDirective);
27162705
} else {
@@ -3413,8 +3402,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
34133402
}
34143403

34153404

3416-
// Set up $watches for isolate scope and controller bindings. This process
3417-
// only occurs for isolate scopes and new scopes with controllerAs.
3405+
// Set up $watches for isolate scope and controller bindings.
34183406
function initializeDirectiveBindings(scope, attrs, destination, bindings, directive) {
34193407
var removeWatchCollection = [];
34203408
var initialChanges = {};

test/ng/compileSpec.js

+98-139
Original file line numberDiff line numberDiff line change
@@ -6205,154 +6205,113 @@ describe('$compile', function() {
62056205
});
62066206

62076207

6208-
it('should throw noident when missing controllerAs directive property', function() {
6209-
module(function($compileProvider) {
6210-
$compileProvider.directive('noIdent', valueFn({
6211-
templateUrl: 'test.html',
6212-
scope: {
6213-
'data': '=dirData',
6214-
'oneway': '<dirData',
6215-
'str': '@dirStr',
6216-
'fn': '&dirFn'
6217-
},
6218-
controller: function() {},
6219-
bindToController: true
6220-
}));
6221-
});
6222-
inject(function($compile, $rootScope) {
6223-
expect(function() {
6224-
$compile('<div no-ident>')($rootScope);
6225-
}).toThrowMinErr('$compile', 'noident',
6226-
'Cannot bind to controller without identifier for directive \'noIdent\'.');
6227-
});
6228-
});
6229-
6230-
6231-
it('should throw noident when missing controller identifier', function() {
6232-
module(function($compileProvider, $controllerProvider) {
6233-
$controllerProvider.register('myCtrl', function() {});
6234-
$compileProvider.directive('noIdent', valueFn({
6235-
templateUrl: 'test.html',
6236-
scope: {
6237-
'data': '=dirData',
6238-
'oneway': '<dirData',
6239-
'str': '@dirStr',
6240-
'fn': '&dirFn'
6241-
},
6208+
describe('should bind to controller via object notation', function() {
6209+
var controllerOptions = [{
6210+
description: 'no controller identifier',
6211+
controller: 'myCtrl'
6212+
}, {
6213+
description: '"Ctrl as ident" syntax',
6214+
controller: 'myCtrl as myCtrl'
6215+
}, {
6216+
description: 'controllerAs setting',
62426217
controller: 'myCtrl',
6243-
bindToController: true
6244-
}));
6245-
});
6246-
inject(function($compile, $rootScope) {
6247-
expect(function() {
6248-
$compile('<div no-ident>')($rootScope);
6249-
}).toThrowMinErr('$compile', 'noident',
6250-
'Cannot bind to controller without identifier for directive \'noIdent\'.');
6251-
});
6252-
});
6218+
controllerAs: 'myCtrl'
6219+
}],
62536220

6221+
scopeOptions = [{
6222+
description: 'isolate scope',
6223+
scope: {}
6224+
}, {
6225+
description: 'new scope',
6226+
scope: true
6227+
}, {
6228+
description: 'no scope',
6229+
scope: false
6230+
}],
62546231

6255-
it('should bind to controller via object notation (isolate scope)', function() {
6256-
var controllerCalled = false;
6257-
module(function($compileProvider, $controllerProvider) {
6258-
$controllerProvider.register('myCtrl', function() {
6259-
this.check = function() {
6260-
expect(this.data).toEqualData({
6261-
'foo': 'bar',
6262-
'baz': 'biz'
6263-
});
6264-
expect(this.oneway).toEqualData({
6265-
'foo': 'bar',
6266-
'baz': 'biz'
6267-
});
6268-
expect(this.str).toBe('Hello, world!');
6269-
expect(this.fn()).toBe('called!');
6270-
};
6271-
controllerCalled = true;
6272-
if (preAssignBindingsEnabled) {
6273-
this.check();
6274-
} else {
6275-
this.$onInit = this.check;
6276-
}
6277-
});
6278-
$compileProvider.directive('fooDir', valueFn({
6279-
templateUrl: 'test.html',
6280-
bindToController: {
6281-
'data': '=dirData',
6282-
'oneway': '<dirData',
6283-
'str': '@dirStr',
6284-
'fn': '&dirFn'
6285-
},
6286-
scope: {},
6287-
controller: 'myCtrl as myCtrl'
6288-
}));
6289-
});
6290-
inject(function($compile, $rootScope, $templateCache) {
6291-
$templateCache.put('test.html', '<p>isolate</p>');
6292-
$rootScope.fn = valueFn('called!');
6293-
$rootScope.whom = 'world';
6294-
$rootScope.remoteData = {
6295-
'foo': 'bar',
6296-
'baz': 'biz'
6297-
};
6298-
element = $compile('<div foo-dir dir-data="remoteData" ' +
6299-
'dir-str="Hello, {{whom}}!" ' +
6300-
'dir-fn="fn()"></div>')($rootScope);
6301-
$rootScope.$digest();
6302-
expect(controllerCalled).toBe(true);
6303-
});
6304-
});
6232+
templateOptions = [{
6233+
description: 'inline template',
6234+
template: '<p>template</p>'
6235+
}, {
6236+
description: 'templateUrl setting',
6237+
templateUrl: 'test.html'
6238+
}, {
6239+
description: 'no template'
6240+
}];
63056241

6242+
forEach(controllerOptions, function(controllerOption) {
6243+
forEach(scopeOptions, function(scopeOption) {
6244+
forEach(templateOptions, function(templateOption) {
6245+
6246+
var description = [],
6247+
ddo = {
6248+
bindToController: {
6249+
'data': '=dirData',
6250+
'oneway': '<dirData',
6251+
'str': '@dirStr',
6252+
'fn': '&dirFn'
6253+
}
6254+
};
63066255

6307-
it('should bind to controller via object notation (new scope)', function() {
6308-
var controllerCalled = false;
6309-
module(function($compileProvider, $controllerProvider) {
6310-
$controllerProvider.register('myCtrl', function() {
6311-
this.check = function() {
6312-
expect(this.data).toEqualData({
6313-
'foo': 'bar',
6314-
'baz': 'biz'
6256+
forEach([controllerOption, scopeOption, templateOption], function(option) {
6257+
description.push(option.description);
6258+
delete option.description;
6259+
extend(ddo, option);
63156260
});
6316-
expect(this.data).toEqualData({
6317-
'foo': 'bar',
6318-
'baz': 'biz'
6261+
6262+
it('(' + description.join(', ') + ')', function() {
6263+
var controllerCalled = false;
6264+
module(function($compileProvider, $controllerProvider) {
6265+
$controllerProvider.register('myCtrl', function() {
6266+
this.check = function() {
6267+
expect(this.data).toEqualData({
6268+
'foo': 'bar',
6269+
'baz': 'biz'
6270+
});
6271+
expect(this.oneway).toEqualData({
6272+
'foo': 'bar',
6273+
'baz': 'biz'
6274+
});
6275+
expect(this.str).toBe('Hello, world!');
6276+
expect(this.fn()).toBe('called!');
6277+
};
6278+
controllerCalled = true;
6279+
if (preAssignBindingsEnabled) {
6280+
this.check();
6281+
} else {
6282+
this.$onInit = this.check;
6283+
}
6284+
});
6285+
$compileProvider.directive('fooDir', valueFn(ddo));
6286+
});
6287+
inject(function($compile, $rootScope, $templateCache) {
6288+
$templateCache.put('test.html', '<p>template</p>');
6289+
$rootScope.fn = valueFn('called!');
6290+
$rootScope.whom = 'world';
6291+
$rootScope.remoteData = {
6292+
'foo': 'bar',
6293+
'baz': 'biz'
6294+
};
6295+
element = $compile('<div foo-dir dir-data="remoteData" ' +
6296+
'dir-str="Hello, {{whom}}!" ' +
6297+
'dir-fn="fn()"></div>')($rootScope);
6298+
$rootScope.$digest();
6299+
expect(controllerCalled).toBe(true);
6300+
if (ddo.controllerAs || ddo.controller.indexOf(' as ') !== -1) {
6301+
if (ddo.scope) {
6302+
expect($rootScope.myCtrl).toBeUndefined();
6303+
} else {
6304+
// The controller identifier was added to the containing scope.
6305+
expect($rootScope.myCtrl).toBeDefined();
6306+
}
6307+
}
6308+
});
63196309
});
6320-
expect(this.str).toBe('Hello, world!');
6321-
expect(this.fn()).toBe('called!');
6322-
};
6323-
controllerCalled = true;
6324-
if (preAssignBindingsEnabled) {
6325-
this.check();
6326-
} else {
6327-
this.$onInit = this.check;
6328-
}
6310+
6311+
});
63296312
});
6330-
$compileProvider.directive('fooDir', valueFn({
6331-
templateUrl: 'test.html',
6332-
bindToController: {
6333-
'data': '=dirData',
6334-
'oneway': '<dirData',
6335-
'str': '@dirStr',
6336-
'fn': '&dirFn'
6337-
},
6338-
scope: true,
6339-
controller: 'myCtrl as myCtrl'
6340-
}));
6341-
});
6342-
inject(function($compile, $rootScope, $templateCache) {
6343-
$templateCache.put('test.html', '<p>isolate</p>');
6344-
$rootScope.fn = valueFn('called!');
6345-
$rootScope.whom = 'world';
6346-
$rootScope.remoteData = {
6347-
'foo': 'bar',
6348-
'baz': 'biz'
6349-
};
6350-
element = $compile('<div foo-dir dir-data="remoteData" ' +
6351-
'dir-str="Hello, {{whom}}!" ' +
6352-
'dir-fn="fn()"></div>')($rootScope);
6353-
$rootScope.$digest();
6354-
expect(controllerCalled).toBe(true);
63556313
});
6314+
63566315
});
63576316

63586317

0 commit comments

Comments
 (0)