diff options
Diffstat (limited to 'docs/content/guide/dev_guide.mvc.understanding_controller.ngdoc')
| -rw-r--r-- | docs/content/guide/dev_guide.mvc.understanding_controller.ngdoc | 346 |
1 files changed, 0 insertions, 346 deletions
diff --git a/docs/content/guide/dev_guide.mvc.understanding_controller.ngdoc b/docs/content/guide/dev_guide.mvc.understanding_controller.ngdoc deleted file mode 100644 index 3cf1940d..00000000 --- a/docs/content/guide/dev_guide.mvc.understanding_controller.ngdoc +++ /dev/null @@ -1,346 +0,0 @@ -@ngdoc overview -@name Developer Guide: About MVC in Angular: Understanding the Controller Component -@description - -# Understanding Controllers - -In Angular, a Controller is a JavaScript **constructor function** that is used to augment the -{@link scope Angular Scope}. - -When a Controller is attached to the DOM via the {@link api/ng.directive:ngController ng-controller} -directive, Angular will instantiate a new Controller object, using the specified Controller's -**constructor function**. A new **child scope** will be available as an injectable parameter to the -Controller's constructor function as `$scope`. - -Use Controllers to: - -- Set up the initial state of the `$scope` object. -- Add behavior to the `$scope` object. - -# Setting up the initial state of a `$scope` object - -Typically, when you create an application you need to set up the initial state for the Angular -`$scope`. You set up the initial state of a scope by attaching properties to the `$scope` object. -The properties contain the **view model** (the model that will be presented by the view). All the -`$scope` properties will be available to the template at the point in the DOM where the Controller -is registered. - -The following example shows a very simple constructor function for a Controller, `GreetingCtrl`, -which attaches a `greeting` property containing the string `'Hola!'` to the `$scope`: - -<pre> - function GreetingCtrl($scope) { - $scope.greeting = 'Hola!'; - } -</pre> - -Once the Controller has been attached to the DOM, the `greeting` property can be data-bound to the -template: - -<pre> - <div ng-controller="GreetingCtrl"> - {{ greeting }} - </div> -</pre> - -**NOTE**: Although Angular allows you to create Controller functions in the global scope, this is -not recommended. In a real application you should use the `.controller` method of your -{@link module Angular Module} for your application as follows: - -<pre> - var myApp = angular.module('myApp',[]); - - myApp.controller('GreetingCtrl', ['$scope', function($scope) { - $scope.greeting = 'Hola!'; - }]); -</pre> - -We have used an **inline injection annotation** to explicitly specify the dependency -of the Controller on the `$scope` service provided by Angular. See the guide on -{@link http://docs.angularjs.org/guide/di Dependency Injection} for more information. - - -# Adding Behavior to a Scope Object - -In order to react to events or execute computation in the view we must provide behavior to the -scope. We add behavior to the scope by attaching methods to the `$scope` object. These methods are -then available to be called from the template/view. - -The following example uses a Controller to add a method to the scope, which doubles a number: - -<pre> - var myApp = angular.module('myApp',[]); - - myApp.controller('DoubleCtrl', ['$scope', function($scope) { - $scope.double = function(value) { return value * 2; }; - }]); -</pre> - -Once the Controller has been attached to the DOM, the `double` method can be invoked in an Angular -expression in the template: - -<pre> - <div ng-controller="DoubleCtrl"> - Two times <input ng-model="num"> equals {{ double(num) }} - </div> -</pre> - -As discussed in the {@link dev_guide.mvc.understanding_model Model} section of this guide, any -objects (or primitives) assigned to the scope become model properties. Any methods assigned to -the scope are available in the template/view, and can be invoked via angular expressions -and `ng` event handler directives (e.g. {@link api/ng.directive:ngClick ngClick}). - -# Using Controllers Correctly - -In general, a Controller shouldn't try to do too much. It should contain only the business logic -needed for a single view. - -The most common way to keep Controllers slim is by encapsulating work that doesn't belong to -controllers into services and then using these services in Controllers via dependency injection. -This is discussed in the {@link di Dependency Injection} {@link dev_guide.services -Services} sections of this guide. - -Do not use Controllers for: - -- Any kind of DOM manipulation — Controllers should contain only business logic. DOM -manipulation (the presentation logic of an application) is well known for being hard to test. -Putting any presentation logic into Controllers significantly affects testability of the business -logic. Angular offers {@link dev_guide.templates.databinding databinding} for automatic DOM manipulation. If -you have to perform your own manual DOM manipulation, encapsulate the presentation logic in -{@link guide/directive directives}. -- Input formatting — Use {@link forms angular form controls} instead. -- Output filtering — Use {@link dev_guide.templates.filters angular filters} instead. -- Sharing stateless or stateful code across Controllers — Use {@link dev_guide.services angular -services} instead. -- Managing the life-cycle of other components (for example, to create service instances). - - -# Associating Controllers with Angular Scope Objects - -You can associate Controllers with scope objects implicitly via the {@link api/ng.directive:ngController ngController -directive} or {@link api/ngRoute.$route $route service}. - - -## Simple Spicy Controller Example - -To illustrate further how Controller components work in Angular, let's create a little app with the -following components: - -- A {@link dev_guide.templates template} with two buttons and a simple message -- A model consisting of a string named `spice` -- A Controller with two functions that set the value of `spice` - -The message in our template contains a binding to the `spice` model, which by default is set to the -string "very". Depending on which button is clicked, the `spice` model is set to `chili` or -`jalapeño`, and the message is automatically updated by data-binding. - -<doc:example module="spicyApp1"> - <doc:source> - <div ng-app="spicyApp1" ng-controller="SpicyCtrl"> - <button ng-click="chiliSpicy()">Chili</button> - <button ng-click="jalapenoSpicy()">Jalapeño</button> - <p>The food is {{spice}} spicy!</p> - </div> - <script> - var myApp = angular.module('spicyApp1', []); - - myApp.controller('SpicyCtrl', ['$scope', function($scope){ - $scope.spice = 'very'; - - $scope.chiliSpicy = function() { - $scope.spice = 'chili'; - }; - - $scope.jalapenoSpicy = function() { - $scope.spice = 'jalapeño'; - }; - }]); - </script> - </doc:source> -</doc:example> - -Things to notice in the example above: - -- The `ng-controller` directive is used to (implicitly) create a scope for our template, and the -scope is augmented (managed) by the `SpicyCtrl` Controller. -- `SpicyCtrl` is just a plain JavaScript function. As an (optional) naming convention the name -starts with capital letter and ends with "Ctrl" or "Controller". -- Assigning a property to `$scope` creates or updates the model. -- Controller methods can be created through direct assignment to scope (see the `chiliSpicy` method) -- The Controller methods and properties are available in the template (for the `<div>` element and -and its children). - -## Spicy Arguments Example - -Controller methods can also take arguments, as demonstrated in the following variation of the -previous example. - -<doc:example module="spicyApp2"> - <doc:source> - <div ng-app="spicyApp2" ng-controller="SpicyCtrl"> - <input ng-model="customSpice"> - <button ng-click="spicy('chili')">Chili</button> - <button ng-click="spicy(customSpice)">Custom spice</button> - <p>The food is {{spice}} spicy!</p> - </div> - <script> - var myApp = angular.module('spicyApp2', []); - - myApp.controller('SpicyCtrl', ['$scope', function($scope){ - $scope.customSpice = "wasabi"; - $scope.spice = 'very'; - - $scope.spicy = function(spice){ - $scope.spice = spice; - }; - }]); - </script> -</doc:source> -</doc:example> - -Notice that the `SpicyCtrl` Controller now defines just one method called `spicy`, which takes one -argument called `spice`. The template then refers to this Controller method and passes in a string -constant `'chili'` in the binding for the first button and a model property `spice` (bound to an -input box) in the second button. - -## Scope Inheritance Example - -It is common to attach Controllers at different levels of the DOM hierarchy. Since the -{@link api/ng.directive:ngController ng-controller} directive creates a new child scope, we get a -hierarchy of scopes that inherit from each other. The `$scope` that each Controller receives will -have access to properties and methods defined by Controllers higher up the hierarchy. -See {@link https://github.com/angular/angular.js/wiki/Understanding-Scopes Understanding Scopes} for -more information about scope inheritance. - -<doc:example module="scopeInheritance"> - <doc:source> - <div ng-app="scopeInheritance" class="spicy"> - <div ng-controller="MainCtrl"> - <p>Good {{timeOfDay}}, {{name}}!</p> - - <div ng-controller="ChildCtrl"> - <p>Good {{timeOfDay}}, {{name}}!</p> - - <div ng-controller="GrandChildCtrl"> - <p>Good {{timeOfDay}}, {{name}}!</p> - </div> - </div> - </div> - </div> - <style> - div.spicy div { - padding: 10px; - border: solid 2px blue; - } - </style> - <script> - var myApp = angular.module('scopeInheritance', []); - myApp.controller('MainCtrl', ['$scope', function($scope){ - $scope.timeOfDay = 'morning'; - $scope.name = 'Nikki'; - }]); - myApp.controller('ChildCtrl', ['$scope', function($scope){ - $scope.name = 'Mattie'; - }]); - myApp.controller('GrandChildCtrl', ['$scope', function($scope){ - $scope.timeOfDay = 'evening'; - $scope.name = 'Gingerbreak Baby'; - }]); - </script> - </doc:source> -</doc:example> - -Notice how we nested three `ng-controller` directives in our template. This will result in four -scopes being created for our view: - -- The root scope -- The `MainCtrl` scope, which contains `timeOfDay` and `name` properties -- The `ChildCtrl` scope, which inherits the `timeOfDay` property but overrides (hides) the `name` -property from the previous -- The `GrandChildCtrl` scope, which overrides (hides) both the `timeOfDay` property defined in `MainCtrl` -and the `name` property defined in `ChildCtrl` - -Inheritance works with methods in the same way as it does with properties. So in our previous -examples, all of the properties could be replaced with methods that return string values. - - -## Testing Controllers - -Although there are many ways to test a Controller, one of the best conventions, shown below, -involves injecting the {@link api/ng.$rootScope $rootScope} and {@link api/ng.$controller $controller}: - -**Controller Definition:** -<pre> - var myApp = angular.module('myApp',[]); - - myApp.controller('MyController', function($scope) { - $scope.spices = [{"name":"pasilla", "spiciness":"mild"}, - {"name":"jalapeno", "spiceiness":"hot hot hot!"}, - {"name":"habanero", "spiceness":"LAVA HOT!!"}]; - $scope.spice = "habanero"; - }); -</pre> - -**Controller Test:** -<pre> -describe('myController function', function() { - - describe('myController', function() { - var $scope; - - beforeEach(module('myApp')); - - beforeEach(inject(function($rootScope, $controller) { - $scope = $rootScope.$new(); - $controller('MyController', {$scope: $scope}); - })); - - it('should create "spices" model with 3 spices', function() { - expect($scope.spices.length).toBe(3); - }); - - it('should set the default value of spice', function() { - expect($scope.spice).toBe('habanero'); - }); - }); -}); -</pre> - - -If you need to test a nested Controller you need to create the same scope hierarchy -in your test that exists in the DOM: - -<pre> -describe('state', function() { - var mainScope, childScope, grandChildScope; - - beforeEach(module('myApp')); - - beforeEach(inject(function($rootScope, $controller) { - mainScope = $rootScope.$new(); - $controller('MainCtrl', {$scope: mainScope}); - childScope = mainScope.$new(); - $controller('ChildCtrl', {$scope: childScope}); - grandChildScope = childScope.$new(); - $controller('GrandChildCtrl', {$scope: grandChildScope}); - })); - - it('should have over and selected', function() { - expect(mainScope.timeOfDay).toBe('morning'); - expect(mainScope.name).toBe('Nikki'); - expect(childScope.timeOfDay).toBe('morning'); - expect(childScope.name).toBe('Mattie'); - expect(grandChildScope.timeOfDay).toBe('evening'); - expect(grandChildScope.name).toBe('Gingerbreak Baby'); - }); -}); -</pre> - - -## Related Topics - -* {@link dev_guide.mvc About MVC in Angular} -* {@link dev_guide.mvc.understanding_model Understanding the Model Component} -* {@link dev_guide.mvc.understanding_view Understanding the View Component} - - |
