mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-03-17 07:40:22 +00:00
178 lines
6.2 KiB
Text
178 lines
6.2 KiB
Text
@workInProgress
|
|
@ngdoc overview
|
|
@name Tutorial: Step 11
|
|
@description
|
|
<table id="tutorial_nav">
|
|
<tr>
|
|
<td id="previous_step">{@link tutorial.step_10 Previous}</td>
|
|
<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-11/app Live Demo
|
|
}</td>
|
|
<td id="tut_home">{@link tutorial Tutorial Home}</td>
|
|
<td id="code_diff">{@link https://github.com/angular/angular-phonecat/compare/step-10...step-11
|
|
Code Diff}</td>
|
|
<td id="next_step">Next</td>
|
|
</tr>
|
|
</table>
|
|
|
|
And so we arrive at the last step of this tutorial. Here we define a custom service that
|
|
represents a {@link http://en.wikipedia.org/wiki/Representational_State_Transfer RESTful} client.
|
|
Using this client we can make xhr requests for data in an easier way, without having to deal with
|
|
the lower-level {@link angular.service.$xhr $xhr} APIs, HTTP methods and URLs.
|
|
|
|
__`app/index.html`.__
|
|
<pre>
|
|
...
|
|
<script src="js/services.js"></script>
|
|
...
|
|
</pre>
|
|
|
|
|
|
__`app/js/services.js`.__ (New)
|
|
<pre>
|
|
angular.service('Phone', function($resource){
|
|
return $resource('phones/:phoneId.json', {}, {
|
|
query: {method:'GET', params:{phoneId:'phones'}, isArray:true}
|
|
});
|
|
});
|
|
</pre>
|
|
|
|
__`app/js/controllers.js`.__
|
|
<pre>
|
|
...
|
|
|
|
function PhoneListCtrl(Phone_) {
|
|
this.orderProp = 'age';
|
|
this.phones = Phone_.query();
|
|
}
|
|
//PhoneListCtrl.$inject = ['Phone'];
|
|
|
|
|
|
function PhoneDetailCtrl(Phone_) {
|
|
this.phone = Phone_.get({phoneId:this.params.phoneId});
|
|
}
|
|
//PhoneDetailCtrl.$inject = ['Phone'];
|
|
</pre>
|
|
|
|
__`test/unit/controllersSpec.js`:__
|
|
<pre>
|
|
/* jasmine specs for controllers go here */
|
|
describe('PhoneCat controllers', function() {
|
|
|
|
beforeEach(function(){
|
|
this.addMatchers({
|
|
toEqualData: function(expected) {
|
|
return angular.equals(this.actual, expected);
|
|
}
|
|
});
|
|
});
|
|
|
|
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).toEqual([]);
|
|
$browser.xhr.flush();
|
|
|
|
expect(ctrl.phones).toEqualData([{name: 'Nexus S'},
|
|
{name: 'Motorola DROID'}]);
|
|
});
|
|
|
|
it('should set the default value of orderProp model', function() {
|
|
expect(ctrl.orderProp).toBe('age');
|
|
});
|
|
});
|
|
|
|
|
|
describe('PhoneDetailCtrl', function(){
|
|
var scope, $browser, ctrl;
|
|
|
|
beforeEach(function() {
|
|
scope = angular.scope();
|
|
$browser = scope.$service('$browser');
|
|
});
|
|
|
|
beforeEach(function() {
|
|
scope = angular.scope();
|
|
$browser = scope.$service('$browser');
|
|
});
|
|
|
|
it('should fetch phone detail', function(){
|
|
scope.params = {phoneId:'xyz'};
|
|
$browser.xhr.expectGET('phones/xyz.json').respond({name:'phone xyz'});
|
|
ctrl = scope.$new(PhoneDetailCtrl);
|
|
|
|
expect(ctrl.phone).toEqualData({});
|
|
$browser.xhr.flush();
|
|
|
|
expect(ctrl.phone).toEqualData({name:'phone xyz'});
|
|
});
|
|
});
|
|
});
|
|
</pre>
|
|
|
|
|
|
## Discussion:
|
|
|
|
* We simplified our sub-controllers (`PhoneListCtrl` and `PhoneDetailCtrl`) by factoring out the
|
|
lower-level `$xhr` service, replacing it with a new service called `Phone`. Angular's {@link
|
|
angular.service.$resource `$resource`} service is easier to use than `$xhr` for interacting with
|
|
data sources exposed as RESTful resources. It is also easier now to understand what the code in
|
|
our controllers is doing.
|
|
|
|
An important thing to notice in our controller code is that we don't pass any callback
|
|
functions when invoking methods of our Phone services. It looks as if the result were returned
|
|
synchronously. That is not the case at all. What is returned synchronously is a "future" — an
|
|
object, which will be filled with data when the xhr response returns. Because of the
|
|
data-binding in angular, we can use this future and bind it to our template. Then, when the
|
|
data arrives, the view will automatically update. See? Angular tries hard to make simple
|
|
stuff simple.
|
|
|
|
* Once again we make use of `$route's` params, this time to construct the URL passed as a
|
|
parameter to `$resource` in our `services.js` script.
|
|
|
|
* Last, but certainly not least, we expanded and modified our unit test to verify that our new
|
|
service is returning data as we expect it to.
|
|
|
|
In our assertions we use a newly-defined `toEqualData` {@link
|
|
http://pivotal.github.com/jasmine/jsdoc/symbols/jasmine.Matchers.html Jasmine matcher}, which
|
|
compares only object properties and ignores methods. This is necessary, because the `$resource`
|
|
client will augment the response object with handy methods for updating and deleting the
|
|
resource (we don't use these in our tutorial though).
|
|
|
|
There you have it! We have created a web app in a relatively short amount of time.
|
|
|
|
## Closing Notes:
|
|
|
|
* For more details and examples of the angular concepts we touched on in this tutorial, see the
|
|
{@link guide Developer Guide}.
|
|
|
|
* For several more examples of sample code, see the {@link cookbook Cookbook}.
|
|
|
|
* When you are ready to start developing a project using angular, be sure to begin with the {@link
|
|
https://github.com/angular/angular-seed angular seed app}.
|
|
|
|
* We hope this tutorial was useful to you, and that you learned enough about angular to make you
|
|
want to learn more. Of course, we especially hope you are inspired to go out and develop angular
|
|
web apps of your own, and perhaps you might even be interested in {@link contribute contributing}
|
|
to angular.
|
|
|
|
<table id="tutorial_nav">
|
|
<tr>
|
|
<td id="previous_step">{@link tutorial.step_10 Previous}</td>
|
|
<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-11/app Live Demo
|
|
}</td>
|
|
<td id="tut_home">{@link tutorial Tutorial Home}</td>
|
|
<td id="code_diff">{@link https://github.com/angular/angular-phonecat/compare/step-10...step-11
|
|
Code Diff}</td>
|
|
<td id="next_step">Next</td>
|
|
</tr>
|
|
</table>
|