diff --git a/src/ng/compile.js b/src/ng/compile.js
index 98c233206f65..7a6121f6e98f 100644
--- a/src/ng/compile.js
+++ b/src/ng/compile.js
@@ -928,6 +928,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
return this;
};
+ this.$$componentControllers = createMap();
/**
* @ngdoc method
* @name $compileProvider#component
@@ -1052,6 +1053,10 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
* See also {@link ng.$compileProvider#directive $compileProvider.directive()}.
*/
this.component = function registerComponent(name, options) {
+ var controller = options.controller || function() {};
+ var ident = identifierForController(options.controller) || options.controllerAs || '$ctrl';
+ this.$$componentControllers[name] = { controller: controller, ident: ident};
+
function factory($injector) {
function makeInjectable(fn) {
if (isFunction(fn) || isArray(fn)) {
@@ -1065,8 +1070,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
var template = (!options.template && !options.templateUrl ? '' : options.template);
return {
- controller: options.controller || function() {},
- controllerAs: identifierForController(options.controller) || options.controllerAs || '$ctrl',
+ controller: controller,
+ controllerAs: ident,
template: makeInjectable(template),
templateUrl: makeInjectable(options.templateUrl),
transclude: options.transclude,
diff --git a/src/ngMock/angular-mocks.js b/src/ngMock/angular-mocks.js
index 6997d83a5dd0..3910cca15baa 100644
--- a/src/ngMock/angular-mocks.js
+++ b/src/ngMock/angular-mocks.js
@@ -2161,6 +2161,34 @@ angular.mock.$ControllerDecorator = ['$delegate', function($delegate) {
};
}];
+/**
+ * @ngdoc service
+ * @name $componentController
+ * @description
+ * A service that can be used to create instances of component controllers.
+ *
+ * Be aware that the controller will be instantiated and attached to the scope as specified in
+ * the component definition object. That means that you must always provide a `$scope` object
+ * in the `locals` param.
+ *
+ * @param {string} componentName the name of the component whose controller we want to instantiate
+ * @param {Object} locals Injection locals for Controller.
+ * @param {Object=} bindings Properties to add to the controller before invoking the constructor. This is used
+ * to simulate the `bindToController` feature and simplify certain kinds of tests.
+ * @param {string=} ident Override the property name to use when attaching the controller to the scope.
+ * @return {Object} Instance of requested controller.
+ */
+angular.mock.$ComponentControllerProvider = ['$compileProvider', function($compileProvider) {
+ return {
+ $get: ['$controller', function($controller) {
+ return function $componentController(componentName, locals, bindings, ident) {
+ var controllerInfo = $compileProvider.$$componentControllers[componentName];
+ return $controller(controllerInfo.controller, locals, bindings, ident || controllerInfo.ident);
+ };
+ }]
+ };
+}];
+
/**
* @ngdoc module
@@ -2184,7 +2212,8 @@ angular.module('ngMock', ['ng']).provider({
$log: angular.mock.$LogProvider,
$interval: angular.mock.$IntervalProvider,
$httpBackend: angular.mock.$HttpBackendProvider,
- $rootElement: angular.mock.$RootElementProvider
+ $rootElement: angular.mock.$RootElementProvider,
+ $componentController: angular.mock.$ComponentControllerProvider
}).config(['$provide', function($provide) {
$provide.decorator('$timeout', angular.mock.$TimeoutDecorator);
$provide.decorator('$$rAF', angular.mock.$RAFDecorator);
diff --git a/test/ngMock/angular-mocksSpec.js b/test/ngMock/angular-mocksSpec.js
index 14fb543eb374..434394143e24 100644
--- a/test/ngMock/angular-mocksSpec.js
+++ b/test/ngMock/angular-mocksSpec.js
@@ -1857,6 +1857,88 @@ describe('ngMock', function() {
});
});
});
+
+
+ describe('$componentController', function() {
+ it('should instantiate a simple controller defined inline in a component', function() {
+ function TestController($scope, a, b) {
+ this.$scope = $scope;
+ this.a = a;
+ this.b = b;
+ }
+ module(function($compileProvider) {
+ $compileProvider.component('test', {
+ controller: TestController
+ });
+ });
+ inject(function($componentController, $rootScope) {
+ var $scope = {};
+ var ctrl = $componentController('test', { $scope: $scope, a: 'A', b: 'B' }, { x: 'X', y: 'Y' });
+ expect(ctrl).toEqual({ $scope: $scope, a: 'A', b: 'B', x: 'X', y: 'Y' });
+ expect($scope.$ctrl).toBe(ctrl);
+ });
+ });
+
+ it('should instantiate a controller with $$inject annotation defined inline in a component', function() {
+ function TestController(x, y, z) {
+ this.$scope = x;
+ this.a = y;
+ this.b = z;
+ }
+ TestController.$inject = ['$scope', 'a', 'b'];
+ module(function($compileProvider) {
+ $compileProvider.component('test', {
+ controller: TestController
+ });
+ });
+ inject(function($componentController, $rootScope) {
+ var $scope = {};
+ var ctrl = $componentController('test', { $scope: $scope, a: 'A', b: 'B' }, { x: 'X', y: 'Y' });
+ expect(ctrl).toEqual({ $scope: $scope, a: 'A', b: 'B', x: 'X', y: 'Y' });
+ expect($scope.$ctrl).toBe(ctrl);
+ });
+ });
+
+ it('should instantiate a named controller defined in a component', function() {
+ function TestController($scope, a, b) {
+ this.$scope = $scope;
+ this.a = a;
+ this.b = b;
+ }
+ module(function($controllerProvider, $compileProvider) {
+ $controllerProvider.register('TestController', TestController);
+ $compileProvider.component('test', {
+ controller: 'TestController'
+ });
+ });
+ inject(function($componentController, $rootScope) {
+ var $scope = {};
+ var ctrl = $componentController('test', { $scope: $scope, a: 'A', b: 'B' }, { x: 'X', y: 'Y' });
+ expect(ctrl).toEqual({ $scope: $scope, a: 'A', b: 'B', x: 'X', y: 'Y' });
+ expect($scope.$ctrl).toBe(ctrl);
+ });
+ });
+
+ it('should instantiate a named controller with `controller as` syntax defined in a component', function() {
+ function TestController($scope, a, b) {
+ this.$scope = $scope;
+ this.a = a;
+ this.b = b;
+ }
+ module(function($controllerProvider, $compileProvider) {
+ $controllerProvider.register('TestController', TestController);
+ $compileProvider.component('test', {
+ controller: 'TestController as testCtrl'
+ });
+ });
+ inject(function($componentController, $rootScope) {
+ var $scope = {};
+ var ctrl = $componentController('test', { $scope: $scope, a: 'A', b: 'B' }, { x: 'X', y: 'Y' });
+ expect(ctrl).toEqual({ $scope: $scope, a: 'A', b: 'B', x: 'X', y: 'Y' });
+ expect($scope.testCtrl).toBe(ctrl);
+ });
+ });
+ });
});