From 678d5451c86b8d5390f7b200f287e2a4b61f0162 Mon Sep 17 00:00:00 2001 From: Martin Staffa Date: Tue, 28 Feb 2017 18:29:59 +0100 Subject: [PATCH 1/2] fix($controller): remove the option to instantiate controllers from constructors on `window` This also removes the likewise deprecated `$controllerProvider.allowGlobals()` method. Closes #15349 BREAKING CHANGE: The option to instantiate controllers from constructors on the global `window` object has been removed. Likewise, the deprecated `$controllerProvider.allowGlobals()` method that could enable this behavior, has been removed. This behavior had been deprecated since AngularJS v1.3.0, because polluting the global scope is bad. To migrate, remove the call to $controllerProvider.allowGlobals() in the config, and register your controller via the Module API or the $controllerProvider, e.g. ``` angular.module('myModule', []).controller('myController', function() {...}); angular.module('myModule', []).config(function($controllerProvider) { $controllerProvider.register('myController', function() {...}); }); ``` --- src/ng/controller.js | 23 ++--------------------- src/ng/directive/ngController.js | 4 ---- src/ngMock/angular-mocks.js | 2 -- test/ng/controllerSpec.js | 15 --------------- 4 files changed, 2 insertions(+), 42 deletions(-) diff --git a/src/ng/controller.js b/src/ng/controller.js index 12a883e3b08e..1d707b243890 100644 --- a/src/ng/controller.js +++ b/src/ng/controller.js @@ -26,8 +26,7 @@ function identifierForController(controller, ident) { * {@link ng.$controllerProvider#register register} method. */ function $ControllerProvider() { - var controllers = {}, - globals = false; + var controllers = {}; /** * @ngdoc method @@ -55,21 +54,6 @@ function $ControllerProvider() { } }; - /** - * @ngdoc method - * @name $controllerProvider#allowGlobals - * @description If called, allows `$controller` to find controller constructors on `window` - * - * @deprecated - * sinceVersion="v1.3.0" - * removeVersion="v1.7.0" - * This method of finding controllers has been deprecated. - */ - this.allowGlobals = function() { - globals = true; - }; - - this.$get = ['$injector', '$window', function($injector, $window) { /** @@ -83,8 +67,6 @@ function $ControllerProvider() { * * * check if a controller with given name is registered via `$controllerProvider` * * check if evaluating the string on the current scope returns a constructor - * * if $controllerProvider#allowGlobals, check `window[constructor]` on the global - * `window` object (deprecated, not recommended) * * The string can use the `controller as property` syntax, where the controller instance is published * as the specified property on the `scope`; the `scope` must be injected into `locals` param for this @@ -124,8 +106,7 @@ function $ControllerProvider() { identifier = identifier || match[3]; expression = controllers.hasOwnProperty(constructor) ? controllers[constructor] - : getter(locals.$scope, constructor, true) || - (globals ? getter($window, constructor, true) : undefined); + : getter(locals.$scope, constructor, true); if (!expression) { throw $controllerMinErr('ctrlreg', diff --git a/src/ng/directive/ngController.js b/src/ng/directive/ngController.js index af339ee4ca5a..014095288000 100644 --- a/src/ng/directive/ngController.js +++ b/src/ng/directive/ngController.js @@ -31,10 +31,6 @@ * The controller instance can be published into a scope property by specifying * `ng-controller="as propertyName"`. * - * If the current `$controllerProvider` is configured to use globals (via - * {@link ng.$controllerProvider#allowGlobals `$controllerProvider.allowGlobals()` }), this may - * also be the name of a globally accessible constructor function (deprecated, not recommended). - * * @example * Here is a simple form for editing user contact information. Adding, removing, clearing, and * greeting are methods declared on the controller (see source tab). These methods can diff --git a/src/ngMock/angular-mocks.js b/src/ngMock/angular-mocks.js index f35f462ec89b..978802bf5b9c 100644 --- a/src/ngMock/angular-mocks.js +++ b/src/ngMock/angular-mocks.js @@ -2256,8 +2256,6 @@ angular.mock.$RootElementProvider = function() { * * * check if a controller with given name is registered via `$controllerProvider` * * check if evaluating the string on the current scope returns a constructor - * * if $controllerProvider#allowGlobals, check `window[constructor]` on the global - * `window` object (deprecated, not recommended) * * The string can use the `controller as property` syntax, where the controller instance is published * as the specified property on the `scope`; the `scope` must be injected into `locals` param for this diff --git a/test/ng/controllerSpec.js b/test/ng/controllerSpec.js index 8fca250c9fba..56bfcf404bbf 100644 --- a/test/ng/controllerSpec.js +++ b/test/ng/controllerSpec.js @@ -95,21 +95,6 @@ describe('$controller', function() { }); - it('should instantiate a controller defined on window if allowGlobals is set', - inject(function($window) { - var scope = {}; - var Foo = function() {}; - - $controllerProvider.allowGlobals(); - - $window.a = {Foo: Foo}; - - var foo = $controller('a.Foo', {$scope: scope}); - expect(foo).toBeDefined(); - expect(foo instanceof Foo).toBe(true); - })); - - it('should throw ctrlfmt if name contains spaces', function() { expect(function() { $controller('ctrl doom'); From 8ea515021e011e39a8c56d7421efb2d73df66c03 Mon Sep 17 00:00:00 2001 From: Martin Staffa Date: Wed, 1 Mar 2017 13:02:13 +0100 Subject: [PATCH 2/2] remove global controller stuff from tutorial --- docs/content/tutorial/step_02.ngdoc | 34 ++++++++--------------------- 1 file changed, 9 insertions(+), 25 deletions(-) diff --git a/docs/content/tutorial/step_02.ngdoc b/docs/content/tutorial/step_02.ngdoc index a9bcc5e22836..ba2edc0b9085 100644 --- a/docs/content/tutorial/step_02.ngdoc +++ b/docs/content/tutorial/step_02.ngdoc @@ -150,38 +150,22 @@ To learn more about AngularJS scopes, see the {@link ng.$rootScope.Scope Angular # Testing -The "AngularJS way" of separating controller from the view, makes it easy to test code as it is being -developed. If our controller were available on the global namespace, we could simply instantiate it -with a mock scope object: +## Testing Controllers -
-```js -describe('PhoneListController', function() { +The "AngularJS way" of separating the controller from the view makes it easy to test code as it is being +developed. In the section "Model and Controller" we have registered our controller via a constructor +function on the `phonecatApp` module. - it('should create a `phones` model with 3 phones', function() { - var scope = {}; - var ctrl = new PhoneListController(scope); - - expect(scope.phones.length).toBe(3); - }); +In tests, we use an AngularJS service, `$controller`, which will retrieve a controller by name. It +also takes a second argument - a map of dependencies that should be injected. -}); -``` +The following test instantiates `PhoneListController` with a mock scope object, +and verifies that the phones array property on the scope contains three records. -The test instantiates `PhoneListController` and verifies that the phones array property on the -scope contains three records. This example demonstrates how easy it is to create a unit test for +This example demonstrates how easy it is to create a unit test for code in AngularJS. Since testing is such a critical part of software development, we make it easy to create tests in AngularJS so that developers are encouraged to write them. - -## Testing non-global Controllers - -In practice, you will not want to have your controller functions in the global namespace. Instead, -you can see that we have registered it via a constructor function on the `phonecatApp` module. - -In this case AngularJS provides a service, `$controller`, which will retrieve your controller by name. -Here is the same test using `$controller`: -
**`app/app.spec.js`:**