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

Commit d54dfec

Browse files
committed
feat($controller): support controller registration via $controllerProvider
It's now possible to register controllers as: .register('MyCtrl', function($scope) { ... }); // or .register('MyCtrl', ['$scope', function($scope) { ... }); Additionally a module loader shortcut api was added as well: myModule.controller('MyCtr', function($scope) { ... });
1 parent 4b8d926 commit d54dfec

File tree

5 files changed

+114
-12
lines changed

5 files changed

+114
-12
lines changed

Diff for: src/loader.js

+12-1
Original file line numberDiff line numberDiff line change
@@ -167,13 +167,24 @@ function setupModuleLoader(window) {
167167
* @ngdoc method
168168
* @name angular.Module#filter
169169
* @methodOf angular.Module
170-
* @param {string} name filter name
170+
* @param {string} name Filter name.
171171
* @param {Function} filterFactory Factory function for creating new instance of filter.
172172
* @description
173173
* See {@link angular.module.ng.$filterProvider#register $filterProvider.register()}.
174174
*/
175175
filter: invokeLater('$filterProvider', 'register'),
176176

177+
/**
178+
* @ngdoc method
179+
* @name angular.Module#controller
180+
* @methodOf angular.Module
181+
* @param {string} name Controller name.
182+
* @param {Function} constructor Controller constructor function.
183+
* @description
184+
* See {@link angular.module.ng.$controllerProvider#register $controllerProvider.register()}.
185+
*/
186+
controller: invokeLater('$controllerProvider', 'register'),
187+
177188
/**
178189
* @ngdoc method
179190
* @name angular.Module#directive

Diff for: src/service/controller.js

+43-8
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,47 @@
11
'use strict';
22

3+
/**
4+
* @ngdoc object
5+
* @name angular.module.ng.$controllerProvider
6+
* @description
7+
* The {@link angular.module.ng.$controller $controller service} is used by Angular to create new
8+
* controllers.
9+
*
10+
* This provider allows controller registration via the
11+
* {@link angular.module.ng.$controllerProvider#register register} method.
12+
*/
313
function $ControllerProvider() {
14+
var controllers = {};
15+
16+
17+
/**
18+
* @ngdoc function
19+
* @name angular.module.ng.$controllerProvider#register
20+
* @methodOf angular.module.ng.$controllerProvider
21+
* @param {string} name Controller name
22+
* @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI
23+
* annotations in the array notation).
24+
*/
25+
this.register = function(name, constructor) {
26+
controllers[name] = constructor;
27+
};
28+
29+
430
this.$get = ['$injector', '$window', function($injector, $window) {
531

632
/**
733
* @ngdoc function
834
* @name angular.module.ng.$controller
935
* @requires $injector
1036
*
11-
* @param {Function|string} Class Constructor function of a controller to instantiate, or
12-
* expression to read from current scope or window.
37+
* @param {Function|string} constructor If called with a function then it's considered to be the
38+
* controller constructor function. Otherwise it's considered to be a string which is used
39+
* to retrieve the controller constructor using the following steps:
40+
*
41+
* * check if a controller with given name is registered via `$controllerProvider`
42+
* * check if evaluating the string on the current scope returns a constructor
43+
* * check `window[constructor]` on the global `window` object
44+
*
1345
* @param {Object} locals Injection locals for Controller.
1446
* @return {Object} Instance of given controller.
1547
*
@@ -20,14 +52,17 @@ function $ControllerProvider() {
2052
* a service, so that one can override this service with {@link https://gist.github.com/1649788
2153
* BC version}.
2254
*/
23-
return function(Class, locals) {
24-
if(isString(Class)) {
25-
var expression = Class;
26-
Class = getter(locals.$scope, expression, true) || getter($window, expression, true);
27-
assertArgFn(Class, expression);
55+
return function(constructor, locals) {
56+
if(isString(constructor)) {
57+
var name = constructor;
58+
constructor = controllers.hasOwnProperty(name)
59+
? controllers[name]
60+
: getter(locals.$scope, name, true) || getter($window, name, true);
61+
62+
assertArgFn(constructor, name, true);
2863
}
2964

30-
return $injector.instantiate(Class, locals);
65+
return $injector.instantiate(constructor, locals);
3166
};
3267
}];
3368
}

Diff for: test/directive/ngViewSpec.js

+19
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,25 @@ describe('ng-view', function() {
5454
});
5555

5656

57+
it('should support string controller declaration', function() {
58+
var MyCtrl = jasmine.createSpy('MyCtrl');
59+
60+
module(function($controllerProvider, $routeProvider) {
61+
$controllerProvider.register('MyCtrl', ['$scope', MyCtrl]);
62+
$routeProvider.when('/foo', {controller: 'MyCtrl', template: '/tpl.html'});
63+
});
64+
65+
inject(function($route, $location, $rootScope, $templateCache) {
66+
$templateCache.put('/tpl.html', [200, '<div></div>', {}]);
67+
$location.path('/foo');
68+
$rootScope.$digest();
69+
70+
expect($route.current.controller).toBe('MyCtrl');
71+
expect(MyCtrl).toHaveBeenCalledWith(element.contents().scope());
72+
});
73+
});
74+
75+
5776
it('should load content via xhr when route changes', function() {
5877
module(function($routeProvider) {
5978
$routeProvider.when('/foo', {template: 'myUrl1'});

Diff for: test/loaderSpec.js

+2
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ describe('module loader', function() {
3838
value('k', 'v').
3939
filter('f', 'ff').
4040
directive('d', 'dd').
41+
controller('ctrl', 'ccc').
4142
config('init2').
4243
constant('abc', 123).
4344
run('runBlock')).toBe(myModule);
@@ -52,6 +53,7 @@ describe('module loader', function() {
5253
['$provide', 'value', ['k', 'v'] ],
5354
['$filterProvider', 'register', ['f', 'ff'] ],
5455
['$compileProvider', 'directive', ['d', 'dd'] ],
56+
['$controllerProvider', 'register', ['ctrl', 'ccc']],
5557
['$injector', 'invoke', ['init2'] ]
5658
]);
5759
expect(myModule._runBlocks).toEqual(['runBlock']);

Diff for: test/service/controllerSpec.js

+38-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,47 @@
11
'use strict';
22

33
describe('$controller', function() {
4-
var $controller;
4+
var $controllerProvider, $controller;
55

6-
beforeEach(inject(function($injector) {
7-
$controller = $injector.get('$controller');
6+
beforeEach(module(function(_$controllerProvider_) {
7+
$controllerProvider = _$controllerProvider_;
88
}));
99

10+
11+
beforeEach(inject(function(_$controller_) {
12+
$controller = _$controller_;
13+
}));
14+
15+
16+
describe('provider', function() {
17+
18+
it('should allow registration of controllers', function() {
19+
var FooCtrl = function($scope) { $scope.foo = 'bar' },
20+
scope = {},
21+
ctrl;
22+
23+
$controllerProvider.register('FooCtrl', FooCtrl);
24+
ctrl = $controller('FooCtrl', {$scope: scope});
25+
26+
expect(scope.foo).toBe('bar');
27+
expect(ctrl instanceof FooCtrl).toBe(true);
28+
});
29+
30+
31+
it('should allow registration of controllers annotated with arrays', function() {
32+
var FooCtrl = function($scope) { $scope.foo = 'bar' },
33+
scope = {},
34+
ctrl;
35+
36+
$controllerProvider.register('FooCtrl', ['$scope', FooCtrl]);
37+
ctrl = $controller('FooCtrl', {$scope: scope});
38+
39+
expect(scope.foo).toBe('bar');
40+
expect(ctrl instanceof FooCtrl).toBe(true);
41+
});
42+
});
43+
44+
1045
it('should return instance of given controller class', function() {
1146
var MyClass = function() {},
1247
ctrl = $controller(MyClass);

0 commit comments

Comments
 (0)