diff options
| author | Igor Minar | 2012-01-15 23:28:10 -0800 | 
|---|---|---|
| committer | Igor Minar | 2012-01-17 09:49:37 -0800 | 
| commit | 92af30ce6e99676c71c85bd08962b68629564908 (patch) | |
| tree | 4adf4b56cbf7c9fb6ee9dee8f40dd16fb2199842 /docs/content/tutorial/step_05.ngdoc | |
| parent | 54581d36df74ac128a078aafb3e4b66e0b1599f3 (diff) | |
| download | angular.js-92af30ce6e99676c71c85bd08962b68629564908.tar.bz2 | |
docs(*): various doc fixes
Diffstat (limited to 'docs/content/tutorial/step_05.ngdoc')
| -rw-r--r-- | docs/content/tutorial/step_05.ngdoc | 216 | 
1 files changed, 0 insertions, 216 deletions
| diff --git a/docs/content/tutorial/step_05.ngdoc b/docs/content/tutorial/step_05.ngdoc deleted file mode 100644 index 7bf6f708..00000000 --- a/docs/content/tutorial/step_05.ngdoc +++ /dev/null @@ -1,216 +0,0 @@ -@ngdoc overview -@name Tutorial: 5 - XHRs & Dependency Injection -@description - -<ul doc:tutorial-nav="5"></ul> - - -Enough of building an app with three phones in a hard-coded dataset! Let's fetch a larger dataset -from our server using one of angular's built-in {@link api/angular.module.ng services} called {@link -api/angular.module.ng.$xhr $xhr}. We will use angular's {@link guide/dev_guide.di dependency -injection (DI)} to provide the service to the `PhoneListCtrl` controller. - - -<doc:tutorial-instructions step="5"></doc:tutorial-instructions> - - -You should now see a list of 20 phones. - -The most important changes are listed below. You can see the full diff on {@link -https://github.com/angular/angular-phonecat/compare/step-4...step-5 -GitHub}: - -## Data - -The `app/phones/phone.json` file in your project is a dataset that contains a larger list of phones -stored in the JSON format. - -Following is a sample of the file: -<pre> -[ - { -  "age": 13, -  "id": "motorola-defy-with-motoblur", -  "name": "Motorola DEFY\u2122 with MOTOBLUR\u2122", -  "snippet": "Are you ready for everything life throws your way?" -  ... - }, -... -] -</pre> - - -## Controller - -We'll use angular's {@link api/angular.module.ng.$xhr $xhr} service in our controller to make an HTTP -request to your web server to fetch the data in the `app/phones/phones.json` file. `$xhr` is just -one of several built-in {@link api/angular.module.ng angular services} that handle common operations -in web apps. Angular injects these services for you where you need them. - -Services are managed by angular's {@link guide/dev_guide.di DI subsystem}. Dependency injection -helps to make your web apps both well-structured (e.g., separate components for presentation, data, -and control) and loosely coupled (dependencies between components are not resolved by the -components themselves, but by the DI subsystem). - -__`app/js/controllers.js:`__ -<pre> -function PhoneListCtrl($xhr) { -  var self = this; - -  $xhr('GET', 'phones/phones.json', function(code, response) { -    self.phones = response; -  }); - -  self.orderProp = 'age'; -} - -//PhoneListCtrl.$inject = ['$xhr']; -</pre> - -`$xhr` makes an HTTP GET request to our web server, asking for `phone/phones.json` (the url is -relative to our `index.html` file). The server responds by providing the data in the json file. -(The response might just as well have been dynamically generated by a backend server. To the -browser and our app they both look the same. For the sake of simplicity we used a json file in this -tutorial.) - -The `$xhr` service takes a callback as the last argument. This callback is used to process the -response. We assign the response to the scope controlled by the controller, as a model called -`phones`. Notice that angular detected the json response and parsed it for us! - -To use a service in angular, you simply declare the names of the services you need as arguments to -the controller's constructor function, as follows: - -    function PhoneListCtrl($xhr) {...} - -Angular's dependency injector provides services to your controller when the controller is being -constructed. The dependency injector also takes care of creating any transitive dependencies the -service may have (services often depend upon other services). - -<img src="img/tutorial/xhr_service_final.png"> - - -### '$' Prefix Naming Convention - -You can create your own services, and in fact we will do exactly that in step 11. As a naming -convention, angular's built-in services, Scope methods and a few other angular APIs have a '$' -prefix in front of the name.  Don't use a '$' prefix when naming your services and models, in order -to avoid any possible naming collisions. - -### A Note on Minification - -Since angular infers the controller's dependencies from the names of arguments to the controller's -constructor function, if you were to {@link http://en.wikipedia.org/wiki/Minification_(programming) -minify} the JavaScript code for `PhoneListCtrl` controller, all of its function arguments would be -minified as well, and the dependency injector would not being able to identify services correctly. - -To overcome issues caused by minification, just assign an array with service identifier strings -into the `$inject` property of the controller function, just like the last line in the snippet -(commented out) suggests: - -    PhoneListCtrl.$inject = ['$xhr']; - - -## Test - -__`test/unit/controllersSpec.js`:__ - -Because we started using dependency injection and our controller has dependencies, constructing the -controller in our tests is a bit more complicated. We could use the `new` operator and provide the -constructor with some kind of fake `$xhr` implementation. However, the recommended (and easier) way -is to create a controller in the test environment in the same way that angular does it in the -production code behind the scenes, as follows: - -<pre> -describe('PhoneCat controllers', function() { - -  describe('PhoneListCtrl', function() { -    var scope, $browser, ctrl; - -    beforeEach(function() { -      scope = angular.module.ng.$rootScope.Scope(); -      $browser = scope.$service('$browser'); - -      $browser.xhr.expectGET('phones/phones.json') -          .respond([{name: 'Nexus S'}, -                    {name: 'Motorola DROID'}]); -      ctrl = scope.$new(PhoneListCtrl); -    }); -  }); -</pre> - -We created the controller in the test environment, as follows: - -* We created a root scope object by calling `angular.module.ng.$rootScope.Scope()` - -* We called `scope.$new(PhoneListCtrl)` to get angular to create the child scope associated with -the `PhoneListCtrl` controller - -Because our code now uses the `$xhr` service to fetch the phone list data in our controller, before -we create the `PhoneListCtrl` child scope, we need to tell the testing harness to expect an -incoming request from the controller. To do this we: - -* Use the {@link api/angular.module.ng.$rootScope.Scope#$service `$service`} method to retrieve the `$browser` service, -a service that angular uses to represent various browser APIs. In tests, angular automatically uses -a mock version of this service that allows you to write tests without having to deal with these -native APIs and the global state associated with them. - -* Use the `$browser.xhr.expectGET` method to train the `$browser` object to expect an incoming HTTP -request and tell it what to respond with. Note that the responses are not returned before we call -the `$browser.xhr.flush` method. - -Now, we will make assertions to verify that the `phones` model doesn't exist on the scope, before -the response is received: - -<pre> -    it('should create "phones" model with 2 phones fetched from xhr', function() { -      expect(ctrl.phones).toBeUndefined(); -      $browser.xhr.flush(); - -      expect(ctrl.phones).toEqual([{name: 'Nexus S'}, -                                   {name: 'Motorola DROID'}]); -    }); -</pre> - -* We flush the xhr queue in the browser by calling `$browser.xhr.flush()`. This causes the callback -we passed into the `$xhr` service to be executed with the trained response. - -* We make the assertions, verifying that the phone model now exists on the scope. - -Finally, we verify that the default value of `orderProp` is set correctly: - -<pre> -    it('should set the default value of orderProp model', function() { -      expect(ctrl.orderProp).toBe('age'); -    }); -  }); -}); -</pre> - -To run the unit tests, execute the `./scripts/test.sh` script and you should see the following -output. - -       Chrome: Runner reset. -       .. -       Total 2 tests (Passed: 2; Fails: 0; Errors: 0) (3.00 ms) -         Chrome 11.0.696.57 Mac OS: Run 2 tests (Passed: 2; Fails: 0; Errors 0) (3.00 ms) - - -# Experiments - -* At the bottom of `index.html`, add a `{{phones}}` binding to see the list of phones displayed in -json format. - -* In the `PhoneListCtrl` controller, pre-process the xhr response by limiting the number of phones -to the first 5 in the list. Use the following code in the xhr callback: - -         self.phones = response.splice(0, 5); - - -# Summary - -Now that you have learned how easy it is to use angular services (thanks to angular's -implementation of dependency injection), go to {@link step_06 step 6}, where you will add some -thumbnail images of phones and some links. - - -<ul doc:tutorial-nav="5"></ul> | 
