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

Commit dd14e0c

Browse files
feat(ngMock.$componentController): add helper to instantiate controllers for components
Closes #13683 Closes #13711
1 parent 7e24590 commit dd14e0c

File tree

3 files changed

+119
-3
lines changed

3 files changed

+119
-3
lines changed

src/ng/compile.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -928,6 +928,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
928928
return this;
929929
};
930930

931+
this.$$componentControllers = createMap();
931932
/**
932933
* @ngdoc method
933934
* @name $compileProvider#component
@@ -1052,6 +1053,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
10521053
* See also {@link ng.$compileProvider#directive $compileProvider.directive()}.
10531054
*/
10541055
this.component = function registerComponent(name, options) {
1056+
var controller = options.controller || function() {};
1057+
var ident = identifierForController(options.controller) || options.controllerAs || '$ctrl';
1058+
this.$$componentControllers[name] = { controller: controller, ident: ident};
1059+
10551060
function factory($injector) {
10561061
function makeInjectable(fn) {
10571062
if (isFunction(fn) || isArray(fn)) {
@@ -1065,8 +1070,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
10651070

10661071
var template = (!options.template && !options.templateUrl ? '' : options.template);
10671072
return {
1068-
controller: options.controller || function() {},
1069-
controllerAs: identifierForController(options.controller) || options.controllerAs || '$ctrl',
1073+
controller: controller,
1074+
controllerAs: ident,
10701075
template: makeInjectable(template),
10711076
templateUrl: makeInjectable(options.templateUrl),
10721077
transclude: options.transclude,

src/ngMock/angular-mocks.js

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2161,6 +2161,34 @@ angular.mock.$ControllerDecorator = ['$delegate', function($delegate) {
21612161
};
21622162
}];
21632163

2164+
/**
2165+
* @ngdoc service
2166+
* @name $componentController
2167+
* @description
2168+
* A service that can be used to create instances of component controllers.
2169+
* <div class="alert alert-info">
2170+
* Be aware that the controller will be instantiated and attached to the scope as specified in
2171+
* the component definition object. That means that you must always provide a `$scope` object
2172+
* in the `locals` param.
2173+
* </div>
2174+
* @param {string} componentName the name of the component whose controller we want to instantiate
2175+
* @param {Object} locals Injection locals for Controller.
2176+
* @param {Object=} bindings Properties to add to the controller before invoking the constructor. This is used
2177+
* to simulate the `bindToController` feature and simplify certain kinds of tests.
2178+
* @param {string=} ident Override the property name to use when attaching the controller to the scope.
2179+
* @return {Object} Instance of requested controller.
2180+
*/
2181+
angular.mock.$ComponentControllerProvider = ['$compileProvider', function($compileProvider) {
2182+
return {
2183+
$get: ['$controller', function($controller) {
2184+
return function $componentController(componentName, locals, bindings, ident) {
2185+
var controllerInfo = $compileProvider.$$componentControllers[componentName];
2186+
return $controller(controllerInfo.controller, locals, bindings, ident || controllerInfo.ident);
2187+
};
2188+
}]
2189+
};
2190+
}];
2191+
21642192

21652193
/**
21662194
* @ngdoc module
@@ -2184,7 +2212,8 @@ angular.module('ngMock', ['ng']).provider({
21842212
$log: angular.mock.$LogProvider,
21852213
$interval: angular.mock.$IntervalProvider,
21862214
$httpBackend: angular.mock.$HttpBackendProvider,
2187-
$rootElement: angular.mock.$RootElementProvider
2215+
$rootElement: angular.mock.$RootElementProvider,
2216+
$componentController: angular.mock.$ComponentControllerProvider
21882217
}).config(['$provide', function($provide) {
21892218
$provide.decorator('$timeout', angular.mock.$TimeoutDecorator);
21902219
$provide.decorator('$$rAF', angular.mock.$RAFDecorator);

test/ngMock/angular-mocksSpec.js

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1857,6 +1857,88 @@ describe('ngMock', function() {
18571857
});
18581858
});
18591859
});
1860+
1861+
1862+
describe('$componentController', function() {
1863+
it('should instantiate a simple controller defined inline in a component', function() {
1864+
function TestController($scope, a, b) {
1865+
this.$scope = $scope;
1866+
this.a = a;
1867+
this.b = b;
1868+
}
1869+
module(function($compileProvider) {
1870+
$compileProvider.component('test', {
1871+
controller: TestController
1872+
});
1873+
});
1874+
inject(function($componentController, $rootScope) {
1875+
var $scope = {};
1876+
var ctrl = $componentController('test', { $scope: $scope, a: 'A', b: 'B' }, { x: 'X', y: 'Y' });
1877+
expect(ctrl).toEqual({ $scope: $scope, a: 'A', b: 'B', x: 'X', y: 'Y' });
1878+
expect($scope.$ctrl).toBe(ctrl);
1879+
});
1880+
});
1881+
1882+
it('should instantiate a controller with $$inject annotation defined inline in a component', function() {
1883+
function TestController(x, y, z) {
1884+
this.$scope = x;
1885+
this.a = y;
1886+
this.b = z;
1887+
}
1888+
TestController.$inject = ['$scope', 'a', 'b'];
1889+
module(function($compileProvider) {
1890+
$compileProvider.component('test', {
1891+
controller: TestController
1892+
});
1893+
});
1894+
inject(function($componentController, $rootScope) {
1895+
var $scope = {};
1896+
var ctrl = $componentController('test', { $scope: $scope, a: 'A', b: 'B' }, { x: 'X', y: 'Y' });
1897+
expect(ctrl).toEqual({ $scope: $scope, a: 'A', b: 'B', x: 'X', y: 'Y' });
1898+
expect($scope.$ctrl).toBe(ctrl);
1899+
});
1900+
});
1901+
1902+
it('should instantiate a named controller defined in a component', function() {
1903+
function TestController($scope, a, b) {
1904+
this.$scope = $scope;
1905+
this.a = a;
1906+
this.b = b;
1907+
}
1908+
module(function($controllerProvider, $compileProvider) {
1909+
$controllerProvider.register('TestController', TestController);
1910+
$compileProvider.component('test', {
1911+
controller: 'TestController'
1912+
});
1913+
});
1914+
inject(function($componentController, $rootScope) {
1915+
var $scope = {};
1916+
var ctrl = $componentController('test', { $scope: $scope, a: 'A', b: 'B' }, { x: 'X', y: 'Y' });
1917+
expect(ctrl).toEqual({ $scope: $scope, a: 'A', b: 'B', x: 'X', y: 'Y' });
1918+
expect($scope.$ctrl).toBe(ctrl);
1919+
});
1920+
});
1921+
1922+
it('should instantiate a named controller with `controller as` syntax defined in a component', function() {
1923+
function TestController($scope, a, b) {
1924+
this.$scope = $scope;
1925+
this.a = a;
1926+
this.b = b;
1927+
}
1928+
module(function($controllerProvider, $compileProvider) {
1929+
$controllerProvider.register('TestController', TestController);
1930+
$compileProvider.component('test', {
1931+
controller: 'TestController as testCtrl'
1932+
});
1933+
});
1934+
inject(function($componentController, $rootScope) {
1935+
var $scope = {};
1936+
var ctrl = $componentController('test', { $scope: $scope, a: 'A', b: 'B' }, { x: 'X', y: 'Y' });
1937+
expect(ctrl).toEqual({ $scope: $scope, a: 'A', b: 'B', x: 'X', y: 'Y' });
1938+
expect($scope.testCtrl).toBe(ctrl);
1939+
});
1940+
});
1941+
});
18601942
});
18611943

18621944

0 commit comments

Comments
 (0)