aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/loader.js13
-rw-r--r--src/service/controller.js51
-rw-r--r--test/directive/ngViewSpec.js19
-rw-r--r--test/loaderSpec.js2
-rw-r--r--test/service/controllerSpec.js41
5 files changed, 114 insertions, 12 deletions
diff --git a/src/loader.js b/src/loader.js
index fdfdaebd..b25fc40e 100644
--- a/src/loader.js
+++ b/src/loader.js
@@ -167,7 +167,7 @@ function setupModuleLoader(window) {
* @ngdoc method
* @name angular.Module#filter
* @methodOf angular.Module
- * @param {string} name filter name
+ * @param {string} name Filter name.
* @param {Function} filterFactory Factory function for creating new instance of filter.
* @description
* See {@link angular.module.ng.$filterProvider#register $filterProvider.register()}.
@@ -176,6 +176,17 @@ function setupModuleLoader(window) {
/**
* @ngdoc method
+ * @name angular.Module#controller
+ * @methodOf angular.Module
+ * @param {string} name Controller name.
+ * @param {Function} constructor Controller constructor function.
+ * @description
+ * See {@link angular.module.ng.$controllerProvider#register $controllerProvider.register()}.
+ */
+ controller: invokeLater('$controllerProvider', 'register'),
+
+ /**
+ * @ngdoc method
* @name angular.Module#directive
* @methodOf angular.Module
* @param {string} name directive name
diff --git a/src/service/controller.js b/src/service/controller.js
index 229ce14a..fa90f8cd 100644
--- a/src/service/controller.js
+++ b/src/service/controller.js
@@ -1,6 +1,32 @@
'use strict';
+/**
+ * @ngdoc object
+ * @name angular.module.ng.$controllerProvider
+ * @description
+ * The {@link angular.module.ng.$controller $controller service} is used by Angular to create new
+ * controllers.
+ *
+ * This provider allows controller registration via the
+ * {@link angular.module.ng.$controllerProvider#register register} method.
+ */
function $ControllerProvider() {
+ var controllers = {};
+
+
+ /**
+ * @ngdoc function
+ * @name angular.module.ng.$controllerProvider#register
+ * @methodOf angular.module.ng.$controllerProvider
+ * @param {string} name Controller name
+ * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI
+ * annotations in the array notation).
+ */
+ this.register = function(name, constructor) {
+ controllers[name] = constructor;
+ };
+
+
this.$get = ['$injector', '$window', function($injector, $window) {
/**
@@ -8,8 +34,14 @@ function $ControllerProvider() {
* @name angular.module.ng.$controller
* @requires $injector
*
- * @param {Function|string} Class Constructor function of a controller to instantiate, or
- * expression to read from current scope or window.
+ * @param {Function|string} constructor If called with a function then it's considered to be the
+ * controller constructor function. Otherwise it's considered to be a string which is used
+ * to retrieve the controller constructor using the following steps:
+ *
+ * * check if a controller with given name is registered via `$controllerProvider`
+ * * check if evaluating the string on the current scope returns a constructor
+ * * check `window[constructor]` on the global `window` object
+ *
* @param {Object} locals Injection locals for Controller.
* @return {Object} Instance of given controller.
*
@@ -20,14 +52,17 @@ function $ControllerProvider() {
* a service, so that one can override this service with {@link https://gist.github.com/1649788
* BC version}.
*/
- return function(Class, locals) {
- if(isString(Class)) {
- var expression = Class;
- Class = getter(locals.$scope, expression, true) || getter($window, expression, true);
- assertArgFn(Class, expression);
+ return function(constructor, locals) {
+ if(isString(constructor)) {
+ var name = constructor;
+ constructor = controllers.hasOwnProperty(name)
+ ? controllers[name]
+ : getter(locals.$scope, name, true) || getter($window, name, true);
+
+ assertArgFn(constructor, name, true);
}
- return $injector.instantiate(Class, locals);
+ return $injector.instantiate(constructor, locals);
};
}];
}
diff --git a/test/directive/ngViewSpec.js b/test/directive/ngViewSpec.js
index 52aefa3a..636e15a8 100644
--- a/test/directive/ngViewSpec.js
+++ b/test/directive/ngViewSpec.js
@@ -54,6 +54,25 @@ describe('ng-view', function() {
});
+ it('should support string controller declaration', function() {
+ var MyCtrl = jasmine.createSpy('MyCtrl');
+
+ module(function($controllerProvider, $routeProvider) {
+ $controllerProvider.register('MyCtrl', ['$scope', MyCtrl]);
+ $routeProvider.when('/foo', {controller: 'MyCtrl', template: '/tpl.html'});
+ });
+
+ inject(function($route, $location, $rootScope, $templateCache) {
+ $templateCache.put('/tpl.html', [200, '<div></div>', {}]);
+ $location.path('/foo');
+ $rootScope.$digest();
+
+ expect($route.current.controller).toBe('MyCtrl');
+ expect(MyCtrl).toHaveBeenCalledWith(element.contents().scope());
+ });
+ });
+
+
it('should load content via xhr when route changes', function() {
module(function($routeProvider) {
$routeProvider.when('/foo', {template: 'myUrl1'});
diff --git a/test/loaderSpec.js b/test/loaderSpec.js
index dff3787d..b2341a71 100644
--- a/test/loaderSpec.js
+++ b/test/loaderSpec.js
@@ -38,6 +38,7 @@ describe('module loader', function() {
value('k', 'v').
filter('f', 'ff').
directive('d', 'dd').
+ controller('ctrl', 'ccc').
config('init2').
constant('abc', 123).
run('runBlock')).toBe(myModule);
@@ -52,6 +53,7 @@ describe('module loader', function() {
['$provide', 'value', ['k', 'v'] ],
['$filterProvider', 'register', ['f', 'ff'] ],
['$compileProvider', 'directive', ['d', 'dd'] ],
+ ['$controllerProvider', 'register', ['ctrl', 'ccc']],
['$injector', 'invoke', ['init2'] ]
]);
expect(myModule._runBlocks).toEqual(['runBlock']);
diff --git a/test/service/controllerSpec.js b/test/service/controllerSpec.js
index 2c0f8c62..91389013 100644
--- a/test/service/controllerSpec.js
+++ b/test/service/controllerSpec.js
@@ -1,12 +1,47 @@
'use strict';
describe('$controller', function() {
- var $controller;
+ var $controllerProvider, $controller;
- beforeEach(inject(function($injector) {
- $controller = $injector.get('$controller');
+ beforeEach(module(function(_$controllerProvider_) {
+ $controllerProvider = _$controllerProvider_;
}));
+
+ beforeEach(inject(function(_$controller_) {
+ $controller = _$controller_;
+ }));
+
+
+ describe('provider', function() {
+
+ it('should allow registration of controllers', function() {
+ var FooCtrl = function($scope) { $scope.foo = 'bar' },
+ scope = {},
+ ctrl;
+
+ $controllerProvider.register('FooCtrl', FooCtrl);
+ ctrl = $controller('FooCtrl', {$scope: scope});
+
+ expect(scope.foo).toBe('bar');
+ expect(ctrl instanceof FooCtrl).toBe(true);
+ });
+
+
+ it('should allow registration of controllers annotated with arrays', function() {
+ var FooCtrl = function($scope) { $scope.foo = 'bar' },
+ scope = {},
+ ctrl;
+
+ $controllerProvider.register('FooCtrl', ['$scope', FooCtrl]);
+ ctrl = $controller('FooCtrl', {$scope: scope});
+
+ expect(scope.foo).toBe('bar');
+ expect(ctrl instanceof FooCtrl).toBe(true);
+ });
+ });
+
+
it('should return instance of given controller class', function() {
var MyClass = function() {},
ctrl = $controller(MyClass);