| 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
 | @workInProgress
@ngdoc overview
@name Tutorial: Step 5
@description
<table id="tutorial_nav">
<tr>
 <td id="previous_step">{@link tutorial.step_00 Previous}</td>
 <td id="step_result">{@link  http://angular.github.com/angular-phonecat/step-5/app Example}</td>
 <td id="tut_home">{@link tutorial Tutorial Home}</td>
<td id="code_diff">{@link https://github.com/angular/angular-phonecat/compare/step-4...step-5 Code
Diff}</td>
 <td id="next_step">{@link tutorial.step_00 Next}</td>
</tr>
</table>
In this step, the View template remains the same but the Model and Controller change.  We'll
introduce the use of an angular {@link angular.service service}, which we will use to implement an
`XMLHttpRequest` request to communicate with a server. Angular provides the built-in {@link
angular.service.$xhr $xhr} service to make this easy.
The addition of the `$xhr` service to our app gives us the opportunity to talk about {@link
guide.di Dependency Injection} (DI).  The use of DI is another cornerstone of the angular
philosophy. DI helps make your web apps well structured, loosely coupled, and ultimately easier to
test.  
__`app/js/controllers.js:`__
<pre>
/* App Controllers */
function PhoneListCtrl($xhr) {
  var self = this;
  $xhr('GET', 'phones/phones.json', function(code, response) {
    self.phones = response;
  });
  self.orderProp = 'age';
}
//PhoneListCtrl.$inject = ['$xhr'];
</pre>
__`test/unit/controllerSpec.js`:__
<pre>
/* jasmine specs for controllers go here */
describe('PhoneCat controllers', function() {
  describe('PhoneListCtrl', function(){
    var scope, $browser, ctrl;
    beforeEach(function() {
      scope = angular.scope();
      $browser = scope.$service('$browser');
      $browser.xhr.expectGET('phones/phones.json').respond([{name: 'Nexus S'},
                                                            {name: 'Motorola DROID'}]);
      ctrl = scope.$new(PhoneListCtrl);
    });
    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'}]);
    });
    it('should set the default value of orderProp model', function() {
      expect(ctrl.orderProp).toBe('age');
    });
  });
});
</pre>
## Discussion:
* __Services:__ {@link angular.service Services} are substitutable objects managed by angular's
{@link guide.di DI subsystem}.  Angular services simplify some of the standard operations common
to web apps.  Angular provides several built-in services (such as {@link angular.service.$xhr
$xhr}). You can also create your own custom services.
* __Dependency Injection:__ To use an angular service, you simply provide the name of the service
as an argument to the controller's constructor function. The name of the argument is significant,
because angular's {@link guide.di DI subsystem} recognizes the identity of a service by its name,
and provides the name of the service to the controller during the controller's construction. The
dependency injector also takes care of creating any transitive dependencies the service may have
(services often depend upon other services).
  Note: if you minify the javascript code for this controller, all function arguments will be
  minified as well. This will result in the dependency injector not being able to identify
  services correctly. To overcome this issue, just assign an array with service identifier strings
  into the `$inject` property of the controller function.
* __`$xhr`:__ We moved our data set out of the controller and into the file
`app/phones/phones.json` (and added some more phones). We used the `$xhr` service to make a GET
HTTP request to our web server, asking for `phone/phones.json` (the url is relative to our
`index.html` file). The server responds with the contents of the json file, which serves as the
source of our data. Keep in mind that the response might just as well have been dynamically
generated by a sophisticated backend server. To our web server they both look the same, but using
a real backend server to generate a response would make our tutorial unnecessarily complicated.
    Notice that the $xhr service takes a callback as the last parameter. This callback is used to
    process the response. In our case, we just assign the response to the current scope controlled
    by the controller, as a model called `phones`. Have you realized that we didn't even have to
    parse the response? Angular took care of that for us.
* __Testing:__  The unit tests have been expanded. Because of the dependency injection business,
we now need to create the controller the same way that angular does it behind the scenes. For this
reason, we need to:
    * Create a root scope object by calling `angular.scope()`
    * Call `scope.$new(PhoneListCtrl)` to get angular to create the child scope associated with
    our controller.
    At the same time, we need to tell the testing harness that it should expect an incoming
    request from our controller. To do this we:
    * Use the `$service` method to retrieve the `$browser` service - this is a service that in
    angular represents 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.
    * We use the `$browser.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.
    * We then make assertions to verify that the `phones` model doesn't exist on the scope, before
    the response is received.
    * 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.
    * Finally, we make the assertions, verifying that the phone model now exists on the scope.
<table id="tutorial_nav">
<tr>
 <td id="previous_step">{@link tutorial.step_00 Previous}</td>
 <td id="step_result">{@link  http://angular.github.com/angular-phonecat/step-5/app Example}</td>
 <td id="tut_home">{@link tutorial Tutorial Home}</td>
 <td id="code_diff">{@link https://github.com/angular/angular-phonecat/compare/step-4...step-5
 Code Diff}</td>
 <td id="next_step">{@link tutorial.step_00 Next}</td>
</tr>
</table>
 |