aboutsummaryrefslogtreecommitdiffstats
path: root/docs/content/tutorial/step_11.ngdoc
diff options
context:
space:
mode:
authorIgor Minar2011-05-02 10:16:50 -0700
committerIgor Minar2011-06-06 22:28:38 -0700
commit6181ca600d3deced0a054551ff6c704bc17d6b7d (patch)
treebd67f96eea18164c751a08c74d6124cddcc9d890 /docs/content/tutorial/step_11.ngdoc
parent11e9572b952e49b01035e956c412d6095533031a (diff)
downloadangular.js-6181ca600d3deced0a054551ff6c704bc17d6b7d.tar.bz2
new batch of tutorial docs
Diffstat (limited to 'docs/content/tutorial/step_11.ngdoc')
-rw-r--r--docs/content/tutorial/step_11.ngdoc426
1 files changed, 248 insertions, 178 deletions
diff --git a/docs/content/tutorial/step_11.ngdoc b/docs/content/tutorial/step_11.ngdoc
index e383f406..5dc45d90 100644
--- a/docs/content/tutorial/step_11.ngdoc
+++ b/docs/content/tutorial/step_11.ngdoc
@@ -1,178 +1,248 @@
-@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>
+@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>
+
+In this step, you will improve the way our app fetches data.
+
+1. Reset your workspace to Step 11 using:
+
+ git checkout --force step-11
+
+or
+
+ ./goto_step.sh 11
+
+2. Refresh your browser or check the app out on {@link
+http://angular.github.com/angular-phonecat/step-11/app our server}.
+
+
+The last improvement we will make to our app is to 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} API, HTTP methods and URLs.
+
+The most important changes are listed below. You can see the full diff on {@link
+https://github.com/angular/angular-phonecat/compare/step-10...step-11
+GitHub}:
+
+
+## Template
+
+The custom service is defined in `app/js/services.js` so we need to include this file in our
+layout template:
+
+__`app/index.html`.__
+<pre>
+...
+ <script src="js/services.js"></script>
+...
+</pre>
+
+## Service
+
+__`app/js/services.js`.__
+<pre>
+ angular.service('Phone', function($resource){
+ return $resource('phones/:phoneId.json', {}, {
+ query: {method:'GET', params:{phoneId:'phones'}, isArray:true}
+ });
+ });
+</pre>
+
+We used the {@link angular.service} API to register a custom service. We passed in the name of the
+service - 'Phone' - and a factory function. The factory function is similar to a controller's
+constructor in that both can declare dependencies via function arguments. The Phone service
+declared a dependency on the `$resource` service.
+
+The `{@link angular.service.$resource $resource}` service makes it easy to create a {@link
+http://en.wikipedia.org/wiki/Representational_State_Transfer RESTful} client with just a few lines
+of code. This client can then be used in our application, instead of the lower-level `$xhr`
+service.
+
+
+## Controller
+
+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.
+
+__`app/js/controllers.js`.__
+<pre>
+...
+
+function PhoneListCtrl(Phone_) {
+ this.orderProp = 'age';
+ this.phones = Phone_.query();
+}
+//PhoneListCtrl.$inject = ['Phone'];
+
+
+function PhoneDetailCtrl(Phone_) {
+ var self = this;
+
+ self.phone = Phone_.get({phoneId: self.params.phoneId}, function(phone) {
+ self.mainImageUrl = phone.images[0];
+ });
+
+ ...
+}
+//PhoneDetailCtrl.$inject = ['Phone'];
+</pre>
+
+Notice how in `PhoneListCtrl` we replaced:
+
+ $xhr('GET', 'phones/phones.json', function(code, response) {
+ self.phones = response;
+ });
+
+with:
+
+ this.phones = Phone_.query();
+
+This is a simple statement that we want to query for all phones.
+
+An important thing to notice in the code above is that we don't pass any callback functions when
+invoking methods of our Phone service. Although 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.
+
+Sometimes, relying on the future object and data-binding alone is not sufficient to do everything
+we require, so in these cases, we can add a callback to process the server response. The
+`PhoneDetailCtrl` controller illustrates this by setting the `mainImageUrl` in a callback.
+
+
+
+
+## Test
+
+We have modified our unit tests to verify that our new service is issuing HTTP requests and
+processing them as expected. The tests also check that our controllers are interacting with the
+service correctly.
+
+The `$resource` client augments the response object with methods for updating and deleting the
+resource. If we were to use the standard `toEqual` matcher, our tests would fail because the test
+values would not match the responses exactly. To solve the problem, we use a newly-defined
+`toEqualData` {@link http://pivotal.github.com/jasmine/jsdoc/symbols/jasmine.Matchers.html Jasmine
+matcher}. When the `toEqualData` matcher compares two objects, it takes only object properties
+into account and ignores methods.
+
+
+__`test/unit/controllersSpec.js`:__
+<pre>
+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>
+
+To run the unit tests, execute the `./scripts/test.sh` script and you should see the following
+output.
+
+ Chrome: Runner reset.
+ ....
+ Total 4 tests (Passed: 4; Fails: 0; Errors: 0) (3.00 ms)
+ Chrome 11.0.696.57 Mac OS: Run 4 tests (Passed: 4; Fails: 0; Errors 0) (3.00 ms)
+
+
+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 code, see the {@link cookbook Cookbook}.
+
+* When you are ready to start developing a project using angular, we recommend that you bootstrap
+your development with the {@link https://github.com/angular/angular-seed angular seed} project.
+
+* We hope this tutorial was useful to you and that you learned enough about angular to make you
+want to learn more. We especially hope you are inspired to go out and develop angular web apps of
+your own, and that you might be interested in {@link contribute contributing} to angular.
+
+* If you have questions or feedback or just want to say "hi", please post a message at
+https://groups.google.com/forum/#!forum/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>