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

Commit 3f2232b

Browse files
committed
feat($controller): disable using global controller constructors
With the exception of simple demos, it is not helpful to use globals for controller constructors. This adds a new method to `$controllerProvider` to re-enable the old behavior, but disables this feature by default. BREAKING CHANGE: `$controller` will no longer look for controllers on `window`. The old behavior of looking on `window` for controllers was originally intended for use in examples, demos, and toy apps. We found that allowing global controller functions encouraged poor practices, so we resolved to disable this behavior by default. To migrate, register your controllers with modules rather than exposing them as globals: Before: ```javascript function MyController() { // ... } ``` After: ```javascript angular.module('myApp', []).controller('MyController', [function() { // ... }]); ``` Although it's not recommended, you can re-enable the old behavior like this: ```javascript angular.module('myModule').config(['$controllerProvider', function($controllerProvider) { // this option might be handy for migrating old apps, but please don't use it // in new ones! $controllerProvider.allowGlobals(); }]); ```
1 parent d5305d5 commit 3f2232b

File tree

3 files changed

+44
-16
lines changed

3 files changed

+44
-16
lines changed

Diff for: src/ng/controller.js

+14-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
*/
1313
function $ControllerProvider() {
1414
var controllers = {},
15+
globals = false,
1516
CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/;
1617

1718

@@ -32,6 +33,15 @@ function $ControllerProvider() {
3233
}
3334
};
3435

36+
/**
37+
* @ngdoc method
38+
* @name $controllerProvider#allowGlobals
39+
* @description If called, allows `$controller` to find controller constructors on `window`
40+
*/
41+
this.allowGlobals = function() {
42+
globals = true;
43+
};
44+
3545

3646
this.$get = ['$injector', '$window', function($injector, $window) {
3747

@@ -46,7 +56,8 @@ function $ControllerProvider() {
4656
*
4757
* * check if a controller with given name is registered via `$controllerProvider`
4858
* * check if evaluating the string on the current scope returns a constructor
49-
* * check `window[constructor]` on the global `window` object
59+
* * if $controllerProvider#allowGlobals, check `window[constructor]` on the global
60+
* `window` object (not recommended)
5061
*
5162
* @param {Object} locals Injection locals for Controller.
5263
* @return {Object} Instance of given controller.
@@ -66,7 +77,8 @@ function $ControllerProvider() {
6677
identifier = match[3];
6778
expression = controllers.hasOwnProperty(constructor)
6879
? controllers[constructor]
69-
: getter(locals.$scope, constructor, true) || getter($window, constructor, true);
80+
: getter(locals.$scope, constructor, true) ||
81+
(globals ? getter($window, constructor, true) : undefined);
7082

7183
assertArgFn(expression, constructor, true);
7284
}

Diff for: test/ng/controllerSpec.js

+19-4
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,21 @@ describe('$controller', function() {
6464
$controllerProvider.register('hasOwnProperty', function($scope) {});
6565
}).toThrowMinErr('ng', 'badname', "hasOwnProperty is not a valid controller name");
6666
});
67+
68+
69+
it('should instantiate a controller defined on window if allowGlobals is set',
70+
inject(function($window) {
71+
var scope = {};
72+
var Foo = function() {};
73+
74+
$controllerProvider.allowGlobals();
75+
76+
$window.a = {Foo: Foo};
77+
78+
var foo = $controller('a.Foo', {$scope: scope});
79+
expect(foo).toBeDefined();
80+
expect(foo instanceof Foo).toBe(true);
81+
}));
6782
});
6883

6984

@@ -97,15 +112,15 @@ describe('$controller', function() {
97112
});
98113

99114

100-
it('should instantiate controller defined on window', inject(function($window) {
115+
it('should not instantiate a controller defined on window', inject(function($window) {
101116
var scope = {};
102117
var Foo = function() {};
103118

104119
$window.a = {Foo: Foo};
105120

106-
var foo = $controller('a.Foo', {$scope: scope});
107-
expect(foo).toBeDefined();
108-
expect(foo instanceof Foo).toBe(true);
121+
expect(function () {
122+
$controller('a.Foo', {$scope: scope});
123+
}).toThrow();
109124
}));
110125

111126

Diff for: test/ng/directive/ngControllerSpec.js

+11-10
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@ describe('ngController', function() {
77
$controllerProvider.register('PublicModule', function() {
88
this.mark = 'works';
99
});
10-
}));
11-
beforeEach(inject(function($window) {
12-
$window.Greeter = function($scope) {
10+
11+
var Greeter = function($scope) {
1312
// private stuff (not exported to scope)
1413
this.prefix = 'Hello ';
1514

@@ -22,20 +21,22 @@ describe('ngController', function() {
2221

2322
$scope.protoGreet = bind(this, this.protoGreet);
2423
};
25-
$window.Greeter.prototype = {
24+
Greeter.prototype = {
2625
suffix: '!',
2726
protoGreet: function(name) {
2827
return this.prefix + name + this.suffix;
2928
}
3029
};
30+
$controllerProvider.register('Greeter', Greeter);
3131

32-
$window.Child = function($scope) {
32+
$controllerProvider.register('Child', function($scope) {
3333
$scope.name = 'Adam';
34-
};
34+
});
3535

36-
$window.Public = function() {
36+
$controllerProvider.register('Public', function($scope) {
3737
this.mark = 'works';
38-
};
38+
});
39+
3940
}));
4041

4142
afterEach(function() {
@@ -77,11 +78,11 @@ describe('ngController', function() {
7778

7879

7980
it('should instantiate controller defined on scope', inject(function($compile, $rootScope) {
80-
$rootScope.Greeter = function($scope) {
81+
$rootScope.VojtaGreeter = function($scope) {
8182
$scope.name = 'Vojta';
8283
};
8384

84-
element = $compile('<div ng-controller="Greeter">{{name}}</div>')($rootScope);
85+
element = $compile('<div ng-controller="VojtaGreeter">{{name}}</div>')($rootScope);
8586
$rootScope.$digest();
8687
expect(element.text()).toBe('Vojta');
8788
}));

0 commit comments

Comments
 (0)