Skip to content

Commit 2840aec

Browse files
feat($componentController): provide isolated scope if none is passed (angular#14425)
Closes angular#14425
1 parent 97b3e00 commit 2840aec

File tree

2 files changed

+27
-3
lines changed

2 files changed

+27
-3
lines changed

src/ngMock/angular-mocks.js

+6-3
Original file line numberDiff line numberDiff line change
@@ -2196,8 +2196,8 @@ angular.mock.$ControllerDecorator = ['$delegate', function($delegate) {
21962196
* A service that can be used to create instances of component controllers.
21972197
* <div class="alert alert-info">
21982198
* Be aware that the controller will be instantiated and attached to the scope as specified in
2199-
* the component definition object. That means that you must always provide a `$scope` object
2200-
* in the `locals` param.
2199+
* the component definition object. If you do not provide a `$scope` object in the `locals` param
2200+
* then the helper will create a new isolated scope as a child of `$rootScope`.
22012201
* </div>
22022202
* @param {string} componentName the name of the component whose controller we want to instantiate
22032203
* @param {Object} locals Injection locals for Controller.
@@ -2207,7 +2207,7 @@ angular.mock.$ControllerDecorator = ['$delegate', function($delegate) {
22072207
* @return {Object} Instance of requested controller.
22082208
*/
22092209
angular.mock.$ComponentControllerProvider = ['$compileProvider', function($compileProvider) {
2210-
this.$get = ['$controller','$injector', function($controller,$injector) {
2210+
this.$get = ['$controller','$injector', '$rootScope', function($controller, $injector, $rootScope) {
22112211
return function $componentController(componentName, locals, bindings, ident) {
22122212
// get all directives associated to the component name
22132213
var directives = $injector.get(componentName + 'Directive');
@@ -2225,6 +2225,9 @@ angular.mock.$ComponentControllerProvider = ['$compileProvider', function($compi
22252225
}
22262226
// get the info of the component
22272227
var directiveInfo = candidateDirectives[0];
2228+
// create a scope if needed
2229+
locals = locals || {};
2230+
locals.$scope = locals.$scope || $rootScope.$new(true);
22282231
return $controller(directiveInfo.controller, locals, bindings, ident || directiveInfo.controllerAs);
22292232
};
22302233
}];

test/ngMock/angular-mocksSpec.js

+21
Original file line numberDiff line numberDiff line change
@@ -2089,6 +2089,27 @@ describe('ngMock', function() {
20892089
}).toThrowError('Too many components found');
20902090
});
20912091
});
2092+
2093+
it('should create an isolated child of $rootScope, if no `$scope` local is provided', function() {
2094+
function TestController($scope) {
2095+
this.$scope = $scope;
2096+
}
2097+
module(function($compileProvider) {
2098+
$compileProvider.component('test', {
2099+
controller: TestController
2100+
});
2101+
});
2102+
inject(function($componentController, $rootScope) {
2103+
var $ctrl = $componentController('test');
2104+
expect($ctrl.$scope).toBeDefined();
2105+
expect($ctrl.$scope.$parent).toBe($rootScope);
2106+
// check it is isolated
2107+
$rootScope.a = 17;
2108+
expect($ctrl.$scope.a).toBeUndefined();
2109+
$ctrl.$scope.a = 42;
2110+
expect($rootScope.a).toEqual(17);
2111+
});
2112+
});
20922113
});
20932114
});
20942115

0 commit comments

Comments
 (0)