aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKenneth R. Culp2011-04-29 10:04:40 -0700
committerIgor Minar2011-06-06 22:28:37 -0700
commite205bd7137fd793d223dbe3e020a628f8e7d98f3 (patch)
tree3ee7038d8e0003e528dbcf52ce53da115a4b3b63
parentbd7e68f12f238a9d14e422b94f35d7db91a8db5a (diff)
downloadangular.js-e205bd7137fd793d223dbe3e020a628f8e7d98f3.tar.bz2
Update tutorial docs.
-rw-r--r--[-rwxr-xr-x]docs/tutorial.ngdoc259
-rwxr-xr-xdocs/tutorial.step_0.ngdoc77
-rwxr-xr-xdocs/tutorial.step_1.ngdoc16
-rw-r--r--docs/tutorial.step_10.ngdoc39
-rw-r--r--docs/tutorial.step_11.ngdoc131
-rwxr-xr-xdocs/tutorial.step_2.ngdoc44
-rwxr-xr-xdocs/tutorial.step_3.ngdoc34
-rwxr-xr-xdocs/tutorial.step_4.ngdoc57
-rwxr-xr-xdocs/tutorial.step_5.ngdoc74
-rwxr-xr-xdocs/tutorial.step_6.ngdoc20
-rwxr-xr-xdocs/tutorial.step_7.ngdoc114
-rwxr-xr-xdocs/tutorial.step_8.ngdoc58
-rwxr-xr-xdocs/tutorial.step_9.ngdoc45
-rw-r--r--docs/tutorial_intro.ngdoc155
14 files changed, 688 insertions, 435 deletions
diff --git a/docs/tutorial.ngdoc b/docs/tutorial.ngdoc
index 41b53ccf..a8a51b45 100755..100644
--- a/docs/tutorial.ngdoc
+++ b/docs/tutorial.ngdoc
@@ -1,87 +1,172 @@
-@workInProgress
-@ngdoc overview
-@name Tutorial
-@description
-
-<table id="tutorial_nav">
-<tr>
-<td id="previous_step">Previous</td>
-<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-0/app Example}</td>
-<td id="tut_home">{@link tutorial Tutorial Home}</td>
-<td id="code_diff">Code Diff</td>
-<td id="next_step">{@link tutorial.step_1 Next}</td>
-</tr>
-</table>
-
-Welcome to the angular tutorial! Before you begin, you can check out the finished app here:
-{@link http://angular.github.com/angular-phonecat/step-11/app/ The Completed Tutorial App}. Also,
-if you missed the {@link tutorial_intro Intro to Tutorial} doc, it provides some background info,
-and describes different options you have in working through the tutorial.
-
-We'll begin the tutorial by creating a basic page, and then we'll add functionality to our app on
-each subsequent step.
-
-# Step 0
-The following sample code is our starting point. It is a static HTML page that displays next to
-nothing, but it has everything we need to proceed. You can think of this bit of code as our
-prototype template, consisting of basic HTML tags and some key angular {@link angular.directive
-directives}.
-
-__`app/index.html`:__
-<pre>
-<!doctype html>
-<html xmlns:ng="http://angularjs.org/">
-<head>
- <meta charset="utf-8">
- <title>my angular app</title>
- <link rel="stylesheet" href="css/app.css"/>
-</head>
-<body>
-
- Nothing here yet!
-
- <script src="lib/angular/angular.js" ng:autobind></script>
-</body>
-</html>
-</pre>
-
-## Discussion:
-
-Although our app doesn't appear to do anything dynamic, note the following:
-
-* __... `xmlns:ng="http://angularjs.org"` ...__ This `xmlns` declaration for the `ng` namespace
-must be specified if you use XHTML, or if you are targeting IE older than 9 (regardless of whether
-you are using XHTML or HTML).
-
-* __`<script src="lib/angular/angular.js"` ...__ This downloads the `angular.js` bootstrap script
-and registers a callback that will be executed by the browser when the HTML is fully downloaded.
-When the callback is executed, angular looks for the {@link angular.directive.ng:autobind
-ng:autobind} attribute. If `ng:autobind` is found, it signals angular to compile and manage the
-whole page.
-
- Note: If you elected not to download any tutorial files but still want to try out some angular
- code on your system, you can change the relative path to the `angular.js` script in your
- template from `./lib/angular/angular.js` to the following:
-
- <script src="http://code.angularjs.org/angular-0.9.14.js" ng:autobind></script>
-
- This will bootstrap angular from the angular server instead of from a local file.
-
-* To try this code out in your browser, you need to navigate to the step-0 page (you are currently
-on Step 0 of the tutorial). If your http server is running, navigate to `app/index.html`.
-Remember, this is a relative URL (see the Relative URL section in {@link tutorial_intro Intro to
-Tutorial}). The browser will display the same thing as you would see if you go to
-http://angular.github.com/angular-phonecat/step-0/app (accessible from Example at the bottom of
-the page).
-
-Now we can move on and add some content to our developing web app.
-
-<table id="tutorial_nav">
-<tr>
-<td id="previous_step">Previous</td>
-<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-0/app Example}</td>
-<td id="tut_home">{@link tutorial Tutorial Home}</td>
-<td id="code_diff">Code Diff</td>
-<td id="next_step">{@link tutorial.step_1 Next}</td>
-</tr>
-</table>
+@workInProgress
+@ngdoc overview
+@name Tutorial
+@description
+
+A great way to get introduced to angular is to work through the {@link tutorial.step_0 angular
+tutorial}, which walks you through the construction of an angular web app. The app you will build
+in the tutorial is loosely based on the {@link http://www.google.com/phone/ Google phone gallery
+app}. The {@link http://angular.github.com/angular-phonecat/step-11/app/ end result of our effort}
+is visually simpler, but demonstrates many of the angular features without distractions in the
+form of CSS code.
+
+This tutorial app ends up like a Google phone gallery app, but is originally based on the {@link
+https://github.com/angular/angular-seed angular-seed project}. The angular seed app isn't
+necessary for building angular apps, but it helps you get started quickly and makes the
+development and testing process much easier. Angular-seed includes a simple example, the latest
+angular libraries, test libraries, and scripts. It provides all of these in an environment that
+is pre-configured for developing a typical web app.
+
+Once you set up your tutorial environment, you should be able to get through the material in less
+than a day and you'll have fun doing it. More experienced coders may be able to zip through the
+exercises in an afternoon. In any case, we promise that your time will be well spent!
+
+When you finish the tutorial you will be able to:
+
+* Create a simple dynamic application that works in any browser
+* Define the differences between angular and common JavaScript frameworks
+* Understand angular expressions
+* Understand how data binding works in angular
+* Use the angular-seed project to quickly boot-strap your own projects
+* Create and run tests
+* Identify resources for learning more about angular
+
+You can work through the tutorial in any of the following ways:
+
+* <a href="#UsingGit">Using Git</a>. Use the Git versioning system to get the files for each step.
+* <a href="#UsingSnapshots">Using Snapshots</a>. Download snapshots (files for each step of the
+tutorial) and tinker with them.
+* <a href="#ReadingExamples">Reading the Examples</a>. Read through the examples, and inspect
+results and code on our server.
+
+The first two ways (Git and snapshots) give you a fuller experience, in that you can run the unit
+and end-to-end tests in addition to the tutorial app. They also give you the ability to play
+around with the code and get instant feedback in your browser. The last way (reading through the
+tutorial online) requires no setup on your machine, but you can't run the tests, and it won't be
+as easy to play around with the code.
+
+<a name="PreReqs"></a>
+# Prerequisites for Git and Snapshots
+
+To run the tutorial app and tests on your machine (using Git or the snapshots) you will need the
+following:
+
+* You need to be running on a Mac or Linux machine.
+* An http server running on your system. If you don't already have one installed, you can install
+`node.js` ({@link https://github.com/joyent/node/wiki/Installation node.js install}) or another
+http sever (such as Apache, etc.).
+* Java. This is required for running tests. Angular itself doesn't require Java.
+* A modern browser (including IE8+). Needed for viewing and debugging code.
+* A text editor of your choice.
+
+<a name="UsingGit"></a>
+# Using Git
+
+The following instructions are for developers who are comfortable with Git's versioning system:
+
+1. Check to be sure you have all of the <a href="#PreReqs">prerequisites</a> on your system.
+
+2. Clone the angular-phonecat repository located at {@link
+https://github.com/angular/angular-phonecat angular-phonecat} by running the following command in
+a terminal:
+
+ git clone git://github.com/angular/angular-phonecat.git
+
+ This will create a directory called `angular-phonecat`.
+
+3. In terminal, navigate to the `angular-phonecat` directory and run:
+
+ git checkout step-0
+
+ (You can run `git checkout step-[0-11]` to go to any of the steps in the tutorial).
+
+4. To see the app running in a browser, do the following:
+ * __For node.js users:__
+ 1. Run `./scripts/web-server.js` to start the app server.
+ 2. Open a browser window for the app and navigate to http://localhost:8000/app/index.html.
+
+ * __For other http servers:__
+ 1. Configure the server to serve the files in the `angular-phonecat` directory.
+ 2. Run `./scripts/web-server.js` to start the app server.
+ 3. Navigate in your browser to
+ http://localhost:[*port-number*]/[*context-path*]/app/index.html.
+
+5. To see tests running in a browser, do the following:
+ * __For node.js users:__
+ 1. Run `./scripts/test-server.sh` to start the test web server.
+ 2. Open a browser window for the tests, navigate to http://localhost:9876, and choose
+ "strict mode".
+ * __For other http servers:__
+ 1. Configure the server to serve the files in the `angular-phonecat` directory.
+ 1. Run `./scripts/test-server.sh` to start the test web server.
+ 3. Navigate in your browser to http://localhost:[*port-number*]/, and choose "strict mode".
+
+
+
+<a name="UsingSnapshots"></a>
+# Using Snapshots
+
+Snapshots are the sets of files that reflect the state of the tutorial app at each step. These
+files include the HTML, CSS, and JavaScript for the app, plus Jasmine JavaScript files and Java
+libraries for the test stack. These will let you run the tutorial app and tests, without requiring
+knowledge of Git. You can download and install the snapshot files as follows:
+
+1. Check to be sure you have all of the <a href="#PreReqs">prerequisites</a> on your system.
+
+2. Navigate to [*the angular server*], and download and unzip [*the snapshot file*] to an
+[*install-dir*] of your choosing.
+
+3. Change directories to [*install-dir*]/sandbox.
+
+4. Run the following command:
+ * `./goto_step.sh 0`
+
+ You have to start out at the beginning, which is Step 0. After you set up Step 0, you can skip
+ around between any steps.
+
+1. To see the app running in your browser, do the following:
+ * __For node.js users:__
+ 1. Run `./scripts/web-server.js` to run the web server.
+ 2. Open a browser window for the app and navigate to http://localhost:8000/app/index.html.
+ 3. Open a browser window for the tests, navigate to http://localhost:9876, and choose
+ "strict mode".
+
+ * __For other http servers:__
+ 1. Configure servers to serve the app and test files in the [*install-dir*]/sandbox.
+ 2. Start the server.
+ 3. Navigate in your app browser to
+ http://localhost:[*port-number*]/[*context-path*]/app/index.html.
+ 4. Navigate in your test browser to http://localhost:[*port-number*] and choose "strict
+ mode".
+
+1. To view the tutorial app at different steps, run `./goto_step.sh [0-11]` and then refresh your
+browser. For example, say you're on Step 5 of the tutorial, and you want to see the app in action:
+
+ 1. Run `goto_step.sh 5` from the command line in the `sandbox` directory.
+ 1. Refresh your app browser.
+
+<a name="ReadingExamples"></a>
+# Reading the Examples
+
+If you don't want to set up anything on your local machine, you can read through the tutorial and
+inspect the tutorial files on our servers; doing this will give you a good idea of what angular
+does, but you won't be able to make any code changes and experiment on your own.
+
+To see the running app at each tutorial step, click the "Example" link at the top or bottom of
+each tutorial page.
+
+To view the code differences between tutorial steps, click the Code Diff link at top or bottom of
+each tutorial page. Additions are highlighted in green; deletions are highlighted in red.
+
+
+# Relative URLs
+Throughout the tutorial, we use relative URLs to refer to files hosted on our local http server.
+The absolute URL depends on your configuration. For example, if you are using the node.js server,
+`app/index.html` translates to:
+
+ http://localhost:8000/app/index.html
+
+If you are using your own http server running on port 8080 and the tutorial files are hosted at
+`/angular_tutorial`, `app/index.html` translates to:
+
+ http://localhost:8080/angular_tutorial/app/index.html
diff --git a/docs/tutorial.step_0.ngdoc b/docs/tutorial.step_0.ngdoc
new file mode 100755
index 00000000..6d11d3b0
--- /dev/null
+++ b/docs/tutorial.step_0.ngdoc
@@ -0,0 +1,77 @@
+@workInProgress
+@ngdoc overview
+@name Tutorial: Step 0
+@description
+
+<table id="tutorial_nav">
+<tr>
+<td id="previous_step">{@link tutorial Previous}</td>
+<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-0/app Example}</td>
+<td id="tut_home">{@link tutorial Tutorial Home}</td>
+<td id="code_diff">Code Diff</td>
+<td id="next_step">{@link tutorial.step_1 Next}</td>
+</tr>
+</table>
+
+The following sample code is our starting point. It is a static HTML page that displays next to
+nothing, but it has everything we need to proceed. You can think of this bit of code as our
+prototype template, consisting of basic HTML tags with a pair of angular specific attributes.
+
+__`app/index.html`:__
+<pre>
+<!doctype html>
+<html xmlns:ng="http://angularjs.org/">
+<head>
+ <meta charset="utf-8">
+ <title>my angular app</title>
+ <link rel="stylesheet" href="css/app.css"/>
+</head>
+<body>
+
+ Nothing here yet!
+
+ <script src="lib/angular/angular.js" ng:autobind></script>
+</body>
+</html>
+</pre>
+
+## Discussion:
+
+Although our app doesn't appear to do anything dynamic, note the following:
+
+* __... `xmlns:ng="http://angularjs.org"` ...__ This `xmlns` declaration for the `ng` namespace
+must be specified if you use XHTML, or if you are targeting IE older than 9 (regardless of whether
+you are using XHTML or HTML).
+
+* __`<script src="lib/angular/angular.js"` ...__ This downloads the `angular.js` script and
+registers a callback that will be executed by the browser when the containing HTML page is fully
+downloaded. When the callback is executed, angular looks for the {@link
+angular.directive.ng:autobind ng:autobind} attribute. If `ng:autobind` is found, it signals
+angular to bootstrap and compile and manage the whole html page.
+
+ Note: If you elected not to download any tutorial files but still want to try out some angular
+ code on your system, you can change the relative path to the `angular.js` script in your
+ template from `./lib/angular/angular.js` to the following:
+
+ <script src="http://code.angularjs.org/angular-0.9.14.js" ng:autobind></script>
+
+ This will download the angular script from the angular server instead of from a local file.
+
+* To try this code out in your browser, you need to navigate to the step-0 page (you are currently
+on Step 0 of the tutorial). If your http server is running, navigate to `app/index.html`.
+Remember, this is a relative URL (see the Relative URL section in {@link tutorial Tutorial}). The
+browser will display the same thing as you would see if you go to
+http://angular.github.com/angular-phonecat/step-0/app (accessible from Example link at the bottom
+of the page).
+
+Now we can move on and add some content to our developing web app.
+
+<table id="tutorial_nav">
+<tr>
+<td id="previous_step">{@link tutorial Previous}</td>
+<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-0/app Example}</td>
+<td id="tut_home">{@link tutorial Tutorial Home}</td>
+<td id="code_diff">Code Diff</td>
+<td id="next_step">{@link tutorial.step_1 Next}</td>
+</tr>
+</table>
diff --git a/docs/tutorial.step_1.ngdoc b/docs/tutorial.step_1.ngdoc
index 02688f2e..7b4613b7 100755
--- a/docs/tutorial.step_1.ngdoc
+++ b/docs/tutorial.step_1.ngdoc
@@ -8,13 +8,13 @@
<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-1/app Example}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
<td id="code_diff">
-{@link https://github.com/angular/angular-phonecat/commit/fa2a351f0ede1666041e407c52e4e5daf448c5f8
-Code Diff}</td>
+{@link https://github.com/angular/angular-phonecat/compare/step-0...step-1 Code Diff}</td>
<td id="next_step">{@link tutorial.step_2 Next}</td>
</tr>
</table>
-In this step, we will add basic information about two cell phones.
+Now that we have the basic ingredients in place, let's add some basic information about two cell
+phones to our app.
Note: We will usually include only the new code that we added for each step. In this and
subsequent examples, we will leave out code from the previous step that hasn't changed, for
@@ -58,18 +58,21 @@ __`app/index.html`:__
* For those of you playing along at home on your own web servers, did you switch to Step 1 and
refresh your browsers?
- * __{@link tutorial_intro Using Git:}__
+ * __{@link tutorial Using Git:}__
From your `angular-phonecat` directory, run this command:
git checkout step-1
- * __{@link tutorial_intro Using Snapshots:}__
+ * __{@link tutorial Using Snapshots:}__
From `[install directory]/sandbox`, run this command:
./goto_step.sh 1
+* Now would be a good time to open up `app/index.html` in your browser and see the current state
+of our "application". It's not very exciting, but that's ok.
+
When you're ready, let's move on and start using some angular features to turn this static page
into a dynamic web app.
@@ -79,8 +82,7 @@ into a dynamic web app.
<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-1/app Example}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
<td id="code_diff">
-{@link https://github.com/angular/angular-phonecat/commit/fa2a351f0ede1666041e407c52e4e5daf448c5f8
-Code Diff}</td>
+{@link https://github.com/angular/angular-phonecat/compare/step-0...step-1 Code Diff}</td>
<td id="next_step">{@link tutorial.step_2 Next}</td>
</tr>
</table>
diff --git a/docs/tutorial.step_10.ngdoc b/docs/tutorial.step_10.ngdoc
index a993bee1..2abe3344 100644
--- a/docs/tutorial.step_10.ngdoc
+++ b/docs/tutorial.step_10.ngdoc
@@ -5,20 +5,20 @@
<table id="tutorial_nav">
<tr>
<td id="previous_step">{@link tutorial.step_9 Previous}</td>
-<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-10/app Example}</td>
+<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-10/app Live Demo
+}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
-<td id="code_diff">{@link
-https://github.com/angular/angular-phonecat/commit/abe1e13c7d9e725fdd3b811ca5ec28ea0d973aab Code
-Diff}</td>
+<td id="code_diff">{@link https://github.com/angular/angular-phonecat/compare/step-9...step-10
+Code Diff}</td>
<td id="next_step">{@link tutorial.step_11 Next}</td>
</tr>
</table>
-In this step we will add a phone image swapping feature. We want to be able to click on a
-thumbnail image in the phone details page, and have that action change the large phone image to
-match the selection.
+The phone details view displays one large image of the current phone and several smaller thumbnail
+images. It would be great if we could replace the large image with any of the thumbnails just by
+clicking on the desired thumbnail image. Let's have a look how we can do this with angular.
-__`app/partials/phone-detail.html`.__
+__`app/partials/phone-detail.html`:__
<pre>
<img ng:src="{{mainImageUrl}}" class="phone"/>
@@ -34,7 +34,7 @@ __`app/partials/phone-detail.html`.__
...
</pre>
-__`app/js/controllers.js`.__
+__`app/js/controllers.js`:__
<pre>
...
function PhoneDetailCtrl($xhr) {
@@ -53,7 +53,7 @@ function PhoneDetailCtrl($xhr) {
//PhoneDetailCtrl.$inject = ['$xhr'];
</pre>
-__`test/e2e/scenarios.js`.__
+__`test/e2e/scenarios.js`:__
<pre>
/* jasmine-like end2end tests go here */
...
@@ -68,7 +68,7 @@ __`test/e2e/scenarios.js`.__
expect(binding('phone.name')).toBe('Nexus S');
});
- it('should display "0.large" image as the main phone image', function() {
+ it('should display the first phone image as the main phone image', function() {
expect(element('img.phone').attr('src')).toBe('img/phones/nexus-s.0.jpg');
});
@@ -88,22 +88,23 @@ __`test/e2e/scenarios.js`.__
Adding the phone image swapping feature is fairly straightforward:
-- We defined the `mainImageUrl` model variable in the details controller (`PhoneDetailCtrl`) and
+* We defined the `mainImageUrl` model property in the details controller (`PhoneDetailCtrl`) and
set the default value of `mainImageUrl` to the first image in the array of images.
-- We created a `setImage` controller method to change `mainImageUrl` to the image clicked on by
+* We created a `setImage` controller method to change `mainImageUrl` to the image clicked on by
the user.
-- We registered an `ng:click` handler for thumb images to use the `setImage` controller method.
-- And of course, we added e2e tests for our new feature.
+* We registered an `{@link angular.directive.ng:click ng:click}` handler for thumb images to use
+the `setImage` controller method.
+* We expanded the end-to-end test to verify that our new feature is swapping images correctly.
<table id="tutorial_nav">
<tr>
<td id="previous_step">{@link tutorial.step_9 Previous}</td>
-<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-10/app Example}</td>
+<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-10/app Live Demo
+}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
-<td id="code_diff">{@link
-https://github.com/angular/angular-phonecat/commit/abe1e13c7d9e725fdd3b811ca5ec28ea0d973aab Code
-Diff}</td>
+<td id="code_diff">{@link https://github.com/angular/angular-phonecat/compare/step-9...step-10
+Code Diff}</td>
<td id="next_step">{@link tutorial.step_11 Next}</td>
</tr>
</table>
diff --git a/docs/tutorial.step_11.ngdoc b/docs/tutorial.step_11.ngdoc
index b770caea..34ba7b02 100644
--- a/docs/tutorial.step_11.ngdoc
+++ b/docs/tutorial.step_11.ngdoc
@@ -5,26 +5,23 @@
<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 Example}</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/commit/46e2bc3ff21a1385d6ef1860c5c242f8e0265379 Code
-Diff}</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
-object. Using this client object we can make requests for data in an easier way, without having
-to deal with the lower-level {@link angular.service.$xhr $xhr} APIs.
+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="lib/angular/angular.js" ng:autobind></script>
- <script src="js/controllers.js"></script>
- <script src="js/filters.js"></script>
<script src="js/services.js"></script>
...
</pre>
@@ -41,34 +38,85 @@ __`app/js/services.js`.__ (New)
__`app/js/controllers.js`.__
<pre>
-function PhonesCtrl($route) {
- var self = this;
-
- $route.when('/phones',
- {template:'partials/phone-list.html', controller:PhoneListCtrl});
- $route.when('/phones/:phoneId',
- {template:'partials/phone-detail.html', controller:PhoneDetailCtrl});
- $route.otherwise({redirectTo:'/phones'});
-
- $route.onChange(function(){
- self.params = $route.current.params;
- });
- $route.parent(this);
-}
-//PhonesCtrl.$inject = ['$route'];
+...
-function PhoneListCtrl(Phone) {
+function PhoneListCtrl(Phone_) {
this.orderProp = 'age';
- this.phones = Phone.query();
+ this.phones = Phone_.query();
}
//PhoneListCtrl.$inject = ['Phone'];
-function PhoneDetailCtrl(Phone) {
- this.phone = Phone.get({phoneId:this.params.phoneId});
+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>
@@ -80,9 +128,26 @@ angular.service.$resource `$resource`} service is easier to use than `$xhr` for
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:
@@ -103,11 +168,11 @@ 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 Example}</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/commit/46e2bc3ff21a1385d6ef1860c5c242f8e0265379 Code
-Diff}</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>
diff --git a/docs/tutorial.step_2.ngdoc b/docs/tutorial.step_2.ngdoc
index f78cb2aa..90a50e0e 100755
--- a/docs/tutorial.step_2.ngdoc
+++ b/docs/tutorial.step_2.ngdoc
@@ -7,17 +7,18 @@
<td id="previous_step">{@link tutorial.step_1 Previous}</td>
<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-2/app Example}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
- <td id="code_diff">{@link
- https://github.com/angular/angular-phonecat/commit/02e30dd64e0e5554fbf4d442ade5b1a251f2bf56
- Code Diff}</td>
+<td id="code_diff">{@link https://github.com/angular/angular-phonecat/compare/step-1...step-2 Code
+Diff}</td>
<td id="next_step">{@link tutorial.step_3 Next}</td>
</tr>
</table>
-An important feature of angular is the incorporation of the principles behind {@link
-http://en.wikipedia.org/wiki/Model–View–Controller the MVC design pattern} into client-side web
-apps. With that in mind, let's use a little angular and a little JavaScript to add Model, View,
-and Controller components to our app.
+In the last step, we remembered what a basic, static web page looks like, and now we want to get
+dynamic. There are many ways to do this, but an important feature of angular is the incorporation
+of the principles behind {@link http://en.wikipedia.org/wiki/Model–View–Controller the MVC design
+pattern} into client-side web apps. With that in mind, let's use a little angular and a little
+JavaScript to add Model, View, and Controller components to our app, and change the static page
+into one that is dynamically generated.
Our __View__ component is constructed by angular from this template:
@@ -39,7 +40,7 @@ __`app/index.html`:__
...
</pre>
-Our data __Model__ (a small set of phones in object literal notation) is instantiated within our
+Our data __Model__ (a short list of phones in object literal notation) is instantiated within our
__Controller__ function (`PhoneListCtrl`):
__`app/js/controllers.js`:__
@@ -88,14 +89,15 @@ enclosed in curly braces: `{{phone.name}}` and `{{phone.snippet}}`:
* The curly braces around `phone.name` and `phone.snippet` are an example of {@link
angular.markup angular markup}. The curly braces are shorthand for the angular directive
{@link angular.directive.ng:bind ng:bind}. They indicate to angular that these are template
- binding points. Binding points are locations in the template where angular constructs two-way
+ binding points. Binding points are locations in the template where angular creates
data-binding between the View and the Model. In angular, the View is a projection of the Model
- through the HTML template.
+ through the HTML template. This means that whenever the model changes, angular refreshes the
+ appropriate binding points, which updates the view.
* __Controller:__ At this point, it doesn't appear as if our controller is doing very much
controlling, but it is playing a crucial role: providing context for our data model so we can
-establish two-way data-binding between the model and the view. Note in the following how we
-connected the dots between our presentation, data, and logic components:
+establish data-binding between the model and the view. Note in the following how we connected the
+dots between our presentation, data, and logic components:
* The name of our controller function (in the JavaScript file `controllers.js`) matches the
{@link angular.directive.ng:controller ng:controller} directive in the `<body>` tag
@@ -104,7 +106,6 @@ connected the dots between our presentation, data, and logic components:
binding points are located within the block bounded by the `<body
ng:controller="PhoneListCtrl>` tag.
- So, our controller function becomes the {@link angular.scope scope} of our data model.
Angular uses scopes, along with the information contained in the template, data model, and
controller to keep the Model and View separated but in sync: any changes to the model are
reflected in the view; any changes that occur in the view are reflected in the model.
@@ -114,20 +115,23 @@ literal notation.
* __Testing:__ Ease of testing is another cornerstone of angular's design philosophy. All we are
doing here is showing how easy it is to create a unit test using the technology baked into
-angular. The test verifies that we have some data, and that there are 3 records in the data set.
+angular. The test verifies that we have 3 records in the phones array.
- Angular's testing stack utilizes Jasmine's Behavior-driven Development (BDD) framework. You
- can learn about it on the {@link http://pivotal.github.com/jasmine/ Jasmine home page} and on
- the {@link https://github.com/pivotal/jasmine/wiki Jasmine wiki}.
+ To run this test, make sure you have a {@link tutorial test server running}, and type
+ `./scripts/test.sh` from the command line.
+
+ Angular developers prefer the syntax of Jasmine's Behavior-driven Development (BDD) framework
+ when writing tests. So while Jasmine is not required by angular, we use it to write all tests
+ in this tutorial. You can learn about Jasmine on the {@link http://pivotal.github.com/jasmine/
+ Jasmine home page} and on the {@link https://github.com/pivotal/jasmine/wiki Jasmine wiki}.
<table id="tutorial_nav">
<tr>
<td id="previous_step">{@link tutorial.step_1 Previous}</td>
<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-2/app Example}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
- <td id="code_diff">{@link
- https://github.com/angular/angular-phonecat/commit/02e30dd64e0e5554fbf4d442ade5b1a251f2bf56
- Code Diff}</td>
+<td id="code_diff">{@link https://github.com/angular/angular-phonecat/compare/step-1...step-2 Code
+Diff}</td>
<td id="next_step">{@link tutorial.step_3 Next}</td>
</tr>
</table>
diff --git a/docs/tutorial.step_3.ngdoc b/docs/tutorial.step_3.ngdoc
index 6ebe81e8..b3d3efc2 100755
--- a/docs/tutorial.step_3.ngdoc
+++ b/docs/tutorial.step_3.ngdoc
@@ -14,9 +14,10 @@
</tr>
</table>
-In this step, we will add full text search to our app. We will also write an end-to-end test,
-because a good end-to-end test is a good friend. It stays with your app, keeps an eye on it, and
-quickly detects regressions.
+We did a lot of work in laying the foundation of our app in the last step, so now we'll do
+something simple, and add full text search. We will also write an end-to-end test, because a good
+end-to-end test is a good friend. It stays with your app, keeps an eye on it, and quickly detects
+regressions.
__`app/index.html`:__
<pre>
@@ -66,25 +67,28 @@ angular.Array.filter $filter} utility (added to the repeater) lets a user type i
and immediately see the effects of their search on the phone list. This new code demonstrates the
following:
- * Two-way data-binding. This is one of the very nice features in angular. In this example,
- the data that you type into the input box (named __`query`__) is immediately available as a
- filter in the list repeater (`phone in phones.$filter(`__`query`__`)`). When the page loads,
- angular binds the name of the input box to a variable of the same name in the data model.
- Whenever the data Model changes, the View reflects the change, and vice versa.
+ * Two way Data-binding. This is one of the core features in angular. When the page loads,
+ angular binds the name of the input box to a variable of the same name in the data model and
+ keeps the two in sync.
- * Use of `$filter` in a template. The `$filter` function is one of several built-in utility
- functions that augment JavaScript arrays during their evaluation as angular expressions. An
- {@link Angular.array angular array} is a JavaScript array object with additional functionality
- added. In {@link guide.expression angular expressions}, these array utilities are available as
- methods. (They are prefixed with a $ to avoid naming collisions.)
+In this example, the data that you type into the input box (named __`query`__) is immediately
+available as a filter input in the list repeater (`phone in phones.$filter(`__`query`__`)`).
+Whenever the data model changes and this change causes the input to the repeater to change, the
+repeater will efficiently update the DOM to reflect the current state of the model.
- * How `ng:repeat` automatically shrinks and grows the number of phones in the View, via DOM
+ * Use of `$filter` in a template. The `$filter` function is one of several built-in {@link
+ angular.Array angular functions} that augment JavaScript arrays during their evaluation as
+ angular expressions. In {@link guide.expression angular expressions}, these array utilities are
+ available as array methods. (They are prefixed with a $ to avoid naming collisions.)
+
+ * `ng:repeat` automatically shrinks and grows the number of phones in the View, via DOM
manipulation that is completely transparent to the developer. If you've written any DOM
manipulation code, this should make you happy.
* __CSS:__ We added in some minimal CSS to the file we set up in Step 0: `./css/app.css`.
-* __Testing:__ This end-to-end test shows the following:
+* __Testing:__ To run the end to end test, open http://localhost:8000/test/e2e/runner.html in
+your browser. This end-to-end test shows the following:
* Proof that the search box and the repeater are correctly wired together.
diff --git a/docs/tutorial.step_4.ngdoc b/docs/tutorial.step_4.ngdoc
index 260ad38f..de98eb34 100755
--- a/docs/tutorial.step_4.ngdoc
+++ b/docs/tutorial.step_4.ngdoc
@@ -7,8 +7,7 @@
<td id="previous_step">{@link tutorial.step_3 Previous}</td>
<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-4/app Example}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
-<td id="code_diff">{@link
-https://github.com/angular/angular-phonecat/commit/b56c91f453114347f0cb25e70b1c4fa4f1421763 Code
+<td id="code_diff">{@link https://github.com/angular/angular-phonecat/compare/step-3...step-4 Code
Diff}</td>
<td id="next_step">{@link tutorial.step_5 Next}</td>
</tr>
@@ -85,20 +84,69 @@ describe('PhoneCat controllers', function() {
});
</pre>
+__`test/e2e/scenarios.js`:__
+<pre>
+/* jasmine-like end2end tests go here */
+describe('PhoneCat App', function() {
+
+ describe('Phone list view', function() {
+
+ beforeEach(function() {
+ browser().navigateTo('../../app/index.html');
+ });
+
+
+ it('should filter the phone list as user types into the search box', function() {
+ expect(repeater('.phones li').count()).toBe(3);
+
+ input('query').enter('nexus');
+ expect(repeater('.phones li').count()).toBe(1);
+
+ input('query').enter('motorola');
+ expect(repeater('.phones li').count()).toBe(2);
+ });
+
+
+ it('should be possible to control phone order via the drop down select box', function() {
+ input('query').enter('tablet'); //let's narrow the dataset to make the test assertions
+ shorter
+
+ expect(repeater('.phones li', 'Phone List').column('a')).
+ toEqual(["Motorola XOOM\u2122 with Wi-Fi",
+ "MOTOROLA XOOM\u2122"]);
+
+ select('orderProp').option('alphabetical');
+
+ expect(repeater('.phones li', 'Phone List').column('a')).
+ toEqual(["MOTOROLA XOOM\u2122",
+ "Motorola XOOM\u2122 with Wi-Fi"]);
+ });
+ });
+});
+</pre>
+
## Discussion:
To provide dynamic ordering, we employ another one of angular's "array type augmenters" and let
the data binding do the rest of the work for us:
+* First, we provide a `<select>` element named `orderProp` for our users so they can choose to
+sort the phone list either alphabetically or by the age of the phone. We added the `age` property
+to each phone record so we can sort by that field.
+
* Like {@link angular.Array.filter $filter}, {@link angular.Array.orderBy $orderBy} is a built-in
method available on array objects in angular expressions. In our UI template, we set up a select
box that lets the user set the `orderProp` model variable to one of the string constants: `age` or
`name`.
-* In our controller, we added a line to set the default value of `orderProp` to `age`.
+* In our controller, we added a line to set the default value of `orderProp` to `age`. If we
+don't override the default value, angular uses the value of the first `<option>` element when it
+initializes the data model.
* Our unit test now verifies that our default ordering property is set.
+* We added an end-to-end test to verify that our select box ordering mechanism works properly.
+
* Once again we added a little more CSS to improve the View.
<table id="tutorial_nav">
@@ -106,8 +154,7 @@ box that lets the user set the `orderProp` model variable to one of the string c
<td id="previous_step">{@link tutorial.step_3 Previous}</td>
<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-4/app Example}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
-<td id="code_diff">{@link
-https://github.com/angular/angular-phonecat/commit/b56c91f453114347f0cb25e70b1c4fa4f1421763 Code
+<td id="code_diff">{@link https://github.com/angular/angular-phonecat/compare/step-3...step-4 Code
Diff}</td>
<td id="next_step">{@link tutorial.step_5 Next}</td>
</tr>
diff --git a/docs/tutorial.step_5.ngdoc b/docs/tutorial.step_5.ngdoc
index 3480e437..c28d7bf8 100755
--- a/docs/tutorial.step_5.ngdoc
+++ b/docs/tutorial.step_5.ngdoc
@@ -7,17 +7,16 @@
<td id="previous_step">{@link tutorial.step_4 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/commit/4f0a518557b5c7442568666b211aa79499870276 Code
- Diff}</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_6 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
-`HttpXmlRequest` request to communicate with a server. Angular provides the built-in {@link
-angular.service.$xhr $xhr} service for this purpose.
+`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
@@ -83,27 +82,66 @@ to web apps. Angular provides several built-in services (such as {@link angular
$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 a parameter to the function in which you are using that service. Angular's {@link guide.di DI
-subsystem} recognizes the identity of the service by name, provides it for you when you need it,
-and manages any transitive dependencies the service may have (services often depend upon other
-services).
+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).
-* __`$xhr`:__ We moved our data set out of the controller and into the file `phones/phones.json`.
-This file serves as our data store rather than an actual server (to the browser they look the
-same). We now use the `$xhr` service to return our phone data, which you'll note is still within
-the scope of our controller function.
+ 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.
-* __Testing:__ The unit test has been expanded. It now verifies that the `$xhr` service behaves
-as expected.
+* __`$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_4 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/commit/4f0a518557b5c7442568666b211aa79499870276 Code
- Diff}</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_6 Next}</td>
</tr>
</table>
diff --git a/docs/tutorial.step_6.ngdoc b/docs/tutorial.step_6.ngdoc
index dc7b07ed..09d2c713 100755
--- a/docs/tutorial.step_6.ngdoc
+++ b/docs/tutorial.step_6.ngdoc
@@ -7,8 +7,7 @@
<td id="previous_step">{@link tutorial.step_5 Previous}</td>
<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-6/app Example}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
-<td id="code_diff">{@link
-https://github.com/angular/angular-phonecat/commit/2fb113a4da9b6d19e17627f351f0681befcccdc0 Code
+<td id="code_diff">{@link https://github.com/angular/angular-phonecat/compare/step-5...step-6 Code
Diff}</td>
<td id="next_step">{@link tutorial.step_7 Next}</td>
</tr>
@@ -77,6 +76,17 @@ __`app/phones/phones.json`__ (sample snippet):
]
</pre>
+__`test/e2e/scenarios.js`__:
+<pre>
+...
+ it('should render phone specific links', function() {
+ input('query').enter('nexus');
+ element('.phones li a').click();
+ expect(browser().location().hash()).toBe('/phones/nexus-s');
+ });
+...
+</pre>
+
## Discussion:
* Note that we're using {@link guide.expression angular expressions} enclosed in the now-familiar
@@ -88,13 +98,15 @@ That directive prevents the browser from treating the angular `{{ exppression }}
literally, as it would do if we tried to use markup in a regular `src` attribute. Use `ng:src` to
keep the browser from eagerly making an extra http request to an invalid location.
+* We expanded our end-to-end test to verify that the app is generating correct links to the phone
+views we will implement in the upcoming steps.
+
<table id="tutorial_nav">
<tr>
<td id="previous_step">{@link tutorial.step_5 Previous}</td>
<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-6/app Example}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
-<td id="code_diff">{@link
-https://github.com/angular/angular-phonecat/commit/2fb113a4da9b6d19e17627f351f0681befcccdc0 Code
+<td id="code_diff">{@link https://github.com/angular/angular-phonecat/compare/step-5...step-6 Code
Diff}</td>
<td id="next_step">{@link tutorial.step_7 Next}</td>
</tr>
diff --git a/docs/tutorial.step_7.ngdoc b/docs/tutorial.step_7.ngdoc
index 3b5984b4..aa4209a2 100755
--- a/docs/tutorial.step_7.ngdoc
+++ b/docs/tutorial.step_7.ngdoc
@@ -5,40 +5,60 @@
<table id="tutorial_nav">
<tr>
<td id="previous_step">{@link tutorial.step_6 Previous}</td>
-<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-7/app Example}</td>
+<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-7/app Live Demo
+}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
-<td id="code_diff">{@link
-https://github.com/angular/angular-phonecat/commit/43ff5d76f1c0a464da67d691418e33e6c9d8dbc8 Code
+<td id="code_diff">{@link https://github.com/angular/angular-phonecat/compare/step-6...step-7 Code
Diff}</td>
<td id="next_step">{@link tutorial.step_8 Next}</td>
</tr>
</table>
-In this step we introduce angular's {@link angular.service.$route $route} service. This service
-is usually used in conjunction with the {@link angular.widget.ng:view ng:view} directive. The
-`$route` service makes it easy to wire together controllers, View templates, and the current URL
+Our app is slowly growing and becoming more complex. Up until now, the app provided our users with
+just one view (the list of all phones), and all of our template code was located in the
+`index.html` file. The next step in building our app is the addition of a view that will show
+detailed information about each of the devices in our list.
+
+To add the detailed view, we could expand the `index.html` file to contain template code for both
+views, but that would get messy very quickly. Instead, we are going to turn the `index.html`
+template into what we call a "layout template". This is a template that is common for all views in
+our application. Other "partial templates" are then included into this layout template depending
+on the current "route" — the view that is currently displayed to the user.
+
+Similarly as with templates, angular also allows for controllers and scopes managed by these
+controllers to be nested. We are going to create a "root" controller called `PhoneCatCtrl`, which
+will contain the declaration of routes for the application.
+
+Application routes in angular are declared via the {@link angular.service.$route $route} service.
+This services makes it easy to wire together controllers, View templates, and the current URL
location in the browser. Using this feature we can implement {@link
http://en.wikipedia.org/wiki/Deep_linking deep linking}, which lets us utilize the browser's
-History, and Back and Forward browser navigation.
+History, and Back and Forward browser navigation.
+
+We'll use the $route service to declare that our application consists of two different views: one
+view presents the phone listing, and the other view presents the details for a particular phone.
+Each view will have the template stored in a separate file in the `app/partials/` directory.
+Similarly each view will have a controller associated with it. These will be stored in the
+existing `app/js/controllers.js` file.
-We'll use {@link angular.service.$route $route} to implement two different views for our
-application: one view presents the phone listing, and the other view presents the details for a
-particular phone. We'll use {@link angular.widget.ng:view ng:view} to include one or the other of
-those views in our main layout page (`index.html`). The view presented in the layout page is based
-on which URL the user navigates to.
+The `$route` service is usually used in conjunction with the {@link angular.widget.ng:view
+ng:view} widget. The role of the `ng:view` widget is to include the view template for the current
+route into the layout template, which makes it a perfect fit for our `index.html` template.
-To manage our two different views, we'll move the existing phone list controller into a
-sub-controller, add a second sub-controller to handle the phone details, and we'll create a new
-root controller to implement the routing. (We'll save the implementation of the phone details
-View for the next step.)
+For now we are going to get all the routing going, and move the phone listing template into a
+separate file. We'll save the implementation of the phone details View for the next step.
__`app/index.html`:__
<pre>
-<body ng:controller="PhoneCatCtrl">
...
+<body ng:controller="PhoneCatCtrl">
<ng:view></ng:view>
-...
+
+ <script src="lib/angular/angular.js" ng:autobind></script>
+ <script src="js/controllers.js"></script>
+</body>
+</html>
</pre>
__`app/partials/phone-list.html`:__
@@ -65,6 +85,11 @@ __`app/partials/phone-list.html`:__
</ul>
</pre>
+__`app/partials/phone-list.html`:__
+<pre>
+TBD: detail view for {{params.phoneId}}
+</pre>
+
__`app/js/controller.js`:__
<pre>
/* App Controllers */
@@ -106,53 +131,50 @@ function PhoneDetailCtrl() {}
## Discussion:
-We have many changes to discuss here in Step 7:
-
* __The View.__ Our View template in `index.html` has been reduced down to this:
-`<ng:view></ng:view>`. It is now what we call a "layout template", because it contains
-information common for all views, including the layout of our application. The {@link
-angular.widget.ng:view ng:view} directive behaves like an "include" declaration (it's a
-specialized sibling of the {@link angular.widget.ng:include ng:include} directive) that works
-specifically with the {@link angular.service.$route $route} service. The View template associated
-with the current route definition gets included "between those tags" (there's more to it than a
-simple include, but that explanation will do for now).
-
- * We added two new View templates:
+`<ng:view></ng:view>`. As described above, it is now a "layout template". We added the following
+two new View templates:
- * `app/partials/phone-list.html` for the phone list;
+ * `app/partials/phone-list.html` for the phone list. The phone-list view was formerly our
+ main view. We simply moved the code from `index.html` to here.
- * `app/partials/phone-detail.html` for the phone details (just a stub for this step);
+ * `app/partials/phone-detail.html` for the phone details (just a placeholder template for now).
* __The Controller(s).__ We now have a new root controller (`PhoneCatCtrl`) and two
-sub-controllers (`PhoneListCtrl` and `PhoneDetailCtrl`).
+sub-controllers (`PhoneListCtrl` and `PhoneDetailCtrl`). These inherit the model properties and
+behavior from the root controller.
* __`$route.`__ The root controller's job now is to set up the `$route` configuration:
- * When the fragment part of the URL in the browser ends in "/phones", `$route` grabs the
- `phone-list.html` template, compiles it, and links it with a new scope that is controlled
- by our `PhoneListCtrl` controller.
+ * When the fragment part of the URL in the browser ends in "/phones", `$route` service
+ grabs the `phone-list.html` template, compiles it, and links it with a new scope that is
+ controlled by our `PhoneListCtrl` controller.
* When the URL ends in "/phones/:phoneId", `$route` compiles and links the
`phone-detail.html` template as it did with `phone-list.html`. But note the use of the
- variable `:phoneId` in the `path` parameter of `$route.when()`: `$route` stores that
- portion of the current URL fragment in its current parameters in a property called
- `params.phoneId`. We made the `$route` parameters available to our sub-controllers in the
- `$route.onChange()` function in our root controller. We will use the `phoneId` property
- when we fetch the phone details in Step 8.
+ `:phoneId` parameter declaration in the `path` argument of `$route.when()`: `$route`
+ services provides all the values for variables defined in this way as
+ `$route.current.params` map. In our route, `$route.current.params.phoneId` always holds
+ the current contents of the `:phoneId` portion of the URL. We will use the `phoneId`
+ parameter when we fetch the phone details in Step 8.
* Any other URL fragment gets redirected to `/phones`.
- * __Deep Linking.__ In `$route`'s `onChange()` method, we copied {@link
- http://en.wikipedia.org/wiki/Deep_linking deep linking} parameters to the `params` property in
- the root scope, so we can use them in the child scopes managed by our sub-controllers.
+ * __Controller/Scope inheritance.__ In the function passed into `$route`'s `onChange()`
+ method, we copied url parameters extracted from the current route to the `params` property in
+ the root scope. This property is inherited by child scopes created for our view controllers
+ and accessible by these controllers.
+
+ * __Tests.__ To automatically verify that everything is wired properly, we write end to end
+ tests that navigate to various URLs and verify that the correct view was rendered.
<table id="tutorial_nav">
<tr>
<td id="previous_step">{@link tutorial.step_6 Previous}</td>
-<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-7/app Example}</td>
+<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-7/app Live Demo
+}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
-<td id="code_diff">{@link
-https://github.com/angular/angular-phonecat/commit/43ff5d76f1c0a464da67d691418e33e6c9d8dbc8 Code
+<td id="code_diff">{@link https://github.com/angular/angular-phonecat/compare/step-6...step-7 Code
Diff}</td>
<td id="next_step">{@link tutorial.step_8 Next}</td>
</tr>
diff --git a/docs/tutorial.step_8.ngdoc b/docs/tutorial.step_8.ngdoc
index bf03fdac..ad967085 100755
--- a/docs/tutorial.step_8.ngdoc
+++ b/docs/tutorial.step_8.ngdoc
@@ -5,10 +5,10 @@
<table id="tutorial_nav">
<tr>
<td id="previous_step">{@link tutorial.step_7 Previous}</td>
-<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-8/app Example}</td>
+<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-8/app Live Demo
+}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
-<td id="code_diff">{@link
-https://github.com/angular/angular-phonecat/commit/1f91f571bdd6f1e705ebb303998afe7820ffc6d9 Code
+<td id="code_diff">{@link https://github.com/angular/angular-phonecat/compare/step-7...step-8 Code
Diff}</td>
<td id="next_step">{@link tutorial.step_9 Next}</td>
</tr>
@@ -41,6 +41,7 @@ __`app/partials/phone-details.html`:__
</dl>
</li>
...
+ </li>
<span>Additional Features</span>
<dd>{{phone.additionalFeatures}}</dd>
</li>
@@ -87,23 +88,60 @@ __`app/phones/nexus-s.json`:__ (sample snippet)
}
</pre>
+__`test/unit/controllerSpec.js`:__
+<pre>
+...
+ 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).toBeUndefined();
+ $browser.xhr.flush();
+
+ expect(ctrl.phone).toEqual({name:'phone xyz'});
+ });
+...
+</pre>
+
+__`test/e2e/scenarios.js`:__
+<pre>
+...
+ describe('Phone detail view', function() {
+
+ beforeEach(function() {
+ browser().navigateTo('../../app/index.html#/phones/nexus-s');
+ });
+
+
+ it('should display nexus-s page', function() {
+ expect(binding('phone.name')).toBe('Nexus S');
+ });
+ });
+...
+</pre>
+
## Discussion:
* Phone Details View Template. There is nothing fancy or new here, just note where we use the
-angular `{{ expression }}` markup and directives to project phone data from our model.
+angular `{{ expression }}` markup and directives to project phone data from our model into the
+view.
* Note how we used the `$route` `params` object from the scope managed by the root controller
-(`PhoneCatCtrl`), to construct the path to the phone details requested by the user. The rest of
-this step is simply applying the previously learned concepts and angular APIs to create a large
-template that displays a lot of data about a phone.
+(`PhoneCatCtrl`), to construct the path for the phone details xhr request. The rest of this step
+is simply applying the previously learned concepts and angular APIs to create a large template
+that displays a lot of data about a phone.
+
+* Tests. We updated the existing end to end test and wrote a new unit test that is similar in
+spirit to the one we wrote for the `PhoneListCtrl` controller.
<table id="tutorial_nav">
<tr>
<td id="previous_step">{@link tutorial.step_7 Previous}</td>
-<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-8/app Example}</td>
+<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-8/app Live Demo
+}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
-<td id="code_diff">{@link
-https://github.com/angular/angular-phonecat/commit/1f91f571bdd6f1e705ebb303998afe7820ffc6d9 Code
+<td id="code_diff">{@link https://github.com/angular/angular-phonecat/compare/step-7...step-8 Code
Diff}</td>
<td id="next_step">{@link tutorial.step_9 Next}</td>
</tr>
diff --git a/docs/tutorial.step_9.ngdoc b/docs/tutorial.step_9.ngdoc
index 9fcf095d..36b60e30 100755
--- a/docs/tutorial.step_9.ngdoc
+++ b/docs/tutorial.step_9.ngdoc
@@ -5,10 +5,10 @@
<table id="tutorial_nav">
<tr>
<td id="previous_step">{@link tutorial.step_8 Previous}</td>
-<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-9/app Example}</td>
+<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-9/app Live Demo
+}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
-<td id="code_diff">{@link
-https://github.com/angular/angular-phonecat/commit/975d173ad0768487852387497c086f3c93fb48f6 Code
+<td id="code_diff">{@link https://github.com/angular/angular-phonecat/compare/step-8...step-9 Code
Diff}</td>
<td id="next_step">{@link tutorial.step_10 Next}</td>
</tr>
@@ -16,18 +16,20 @@ Diff}</td>
In this step, we have determined that the built-in angular display filters ({@link
angular.filter.number number}, {@link angular.filter.currency currency}, {@link
-angular.filter.date date}, etc.) do not handle what we want to do, and so we get to create our own
+angular.filter.date date}, etc.) don't handle what we want to do, so we get to create our own
custom {@link angular.filter filter}.
In the previous step, the details page displayed either "true" or "false" to indicate whether
certain phone features were present or not. Our custom "checkmark" filter replaces those text
-strings with images: ✓ for "true", and ✘ for "false".
+strings with glyphs: ✓ for "true", and ✘ for "false".
Our filter code lives in `app/js/filters.js`:
-__`app/index.html`.__
+__`app/index.html`:__
<pre>
...
+ <script src="lib/angular/angular.js" ng:autobind></script>
+ <script src="js/controllers.js"></script>
<script src="app/js/filters.js"></script>
...
</pre>
@@ -35,7 +37,7 @@ __`app/index.html`.__
In the phone details template, we employ our filter for angular expressions whose values are
"true" or "false"; `{{ [phone_feature] | checkmark }}`:
-__`app/partials/phone-detail.html`.__
+__`app/partials/phone-detail.html`:__
<pre>
<img ng:src="{{phone.images[0].large}}" class="phone"/>
<h1>{{phone.name}}</h1>
@@ -62,33 +64,44 @@ __`app/partials/phone-detail.html`.__
</ul>
</pre>
-__`app/js/filters.js`.__ (New)
+__`app/js/filters.js`:__ (New)
<pre>
-/* http://docs.angularjs.org/#!angular.filter */
-
angular.filter('checkmark', function(input) {
return input ? '\u2713' : '\u2718';
});
</pre>
+__`test/unit/filtersSpec.js`:__ (New)
+<pre>
+describe('checkmark filter', function() {
+
+ it('should convert boolean values to unicode checkmark or cross', function() {
+ expect(angular.filter.checkmark(true)).toBe('\u2713');
+ expect(angular.filter.checkmark(false)).toBe('\u2718');
+ });
+})
+</pre>
## Discussion:
-This example shows how easy it is to roll your own filters for displaying data. As explained in
+* This example shows how easy it is to roll your own filters for displaying data. As explained in
the "Writing your own Filters" section of the {@link angular.filter angular.filter} page, you
-simply add your filter function on to the `angular.filter` object.
+simply register your custom filter function on to the `angular.filter` function.
-In this example, our filter name is "checkmark"; our input is either "true" or "false", and we
+* In this example, our filter name is "checkmark"; our input is either "true" or "false", and we
return one of two unicode characters we have chosen to represent true or false (`\u2713` and
`\u2718`).
+* We created a new unit test to verify that our custom filter converts boolean values to unicode
+characters.
+
<table id="tutorial_nav">
<tr>
<td id="previous_step">{@link tutorial.step_8 Previous}</td>
-<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-9/app Example}</td>
+<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-9/app Live Demo
+}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
-<td id="code_diff">{@link
-https://github.com/angular/angular-phonecat/commit/975d173ad0768487852387497c086f3c93fb48f6 Code
+<td id="code_diff">{@link https://github.com/angular/angular-phonecat/compare/step-8...step-9 Code
Diff}</td>
<td id="next_step">{@link tutorial.step_10 Next}</td>
</tr>
diff --git a/docs/tutorial_intro.ngdoc b/docs/tutorial_intro.ngdoc
deleted file mode 100644
index 855f545c..00000000
--- a/docs/tutorial_intro.ngdoc
+++ /dev/null
@@ -1,155 +0,0 @@
-@workInProgress
-@ngdoc overview
-@name Intro to Tutorial
-@description
-
-A great way to get introduced to angular is to work through the {@link Tutorial angular tutorial},
-which walks you through the construction of an angular web app. The app you will build in the
-tutorial is based on the {@link http://www.google.com/phone/# Google phone gallery app}.
-
-Once you set up your tutorial environment, you should be able to get through the material in less
-than a day and you'll have fun doing it. More experienced coders may be able to zip through the
-exercises in an afternoon. In any case, we promise that your time will be well spent!
-
-When you finish the tutorial you will be able to:
-
-* Create a simple dynamic application that works in any browser
-* Define the differences between angular and common JavaScript frameworks
-* Understand angular expressions
-* Understand how data binding works in angular
-* Create your own angular widgets and directives
-* Add your own tags to angular
-* Use the angular-seed project to quickly boot-strap your own projects
-* Create and run tests
-* Identify resources for learning more about angular
-
-You can work through the tutorial in any of the following ways:
-
-* <a href="#UsingGit">Using Git</a>. Use the Git Versioning System to get the files for each step.
-* <a href="#UsingSnapshots">Using Snapshots</a>. Download snapshots (files for each step of the
-tutorial) from the angular server.
-* <a href="#ReadingExamples">Reading the Examples</a>. Read through the examples, and inspect
-results and code on our server.
-
-The first two ways (Git and snapshots) give you a fuller experience, in that you can run the unit
-and end-to-end tests in addition to the tutorial app. They also give you the ability to play
-around with the code and get instant feedback in your browser. The last way (reading through the
-tutorial online) requires no setup on your machine, but you can't run the tests, and it won't be
-as easy to play around with the code.
-
-<a name="PreReqs"></a>
-# Prerequisites for Git and Snapshots
-
-To run the tutorial app and tests on your machine (using Git or the snapshots) you will need the
-following:
-
-* An http server running on your system. If you don't already have one installed, you can install
-`node.js` ({@link https://github.com/joyent/node/wiki/Installation node.js install}) or another
-http sever (such as Apache, etc.).
-* Java. This is required for running tests. Angular itself doesn't require Java.
-* A modern browser. Needed for viewing and debugging code.
-* A text editor of your choice.
-
-<a name="UsingGit"></a>
-# Using Git
-
-The following instructions are for developers who are comfortable with Git's versioning system:
-
-1. Check to be sure you have all of the <a href="#PreReqs">prerequisites</a> on your system.
-
-1. Clone the angular-phonecat repository located at {@link
-https://github.com/angular/angular-phonecat angular-phonecat} by running the following command in
-a terminal:
-
- git clone git://github.com/angular/angular-phonecat.git
-
- This will create a directory called `angular-phonecat`.
-
-1. In terminal, navigate to the `angular-phonecat` directory and run:
-
- git checkout step-0
-
- (You can run `git checkout step-[0-11]` to go to any of the steps in the tutorial).
-
-1. To see the app running in your browser, do the following:
- * __For node.js users:__
- 1. Run `./scripts/web-server.js` to start the web server.
- 1. Open a browser window for the app and navigate to http://localhost:8000/app/index.html.
- 1. Open a browser window for the tests, navigate to http://localhost:9876, and choose
- "strict mode".
-
- * __For other http servers:__
- 1. Configure the server to serve the files in the `angular-phonecat` directory.
- 1. Start the server.
- 1. Navigate in your browser to
- http://localhost:[*port-number*]/[*context-path*]/app/index.html.
- 1. Navigate in your browser to http://localhost:[*port-number*]/, and choose "strict mode".
-
-<a name="UsingSnapshots"></a>
-# Using Snapshots
-
-Snapshots are the sets of files that reflect the state of the tutorial app at each step. These
-files include the HTML, CSS, and JavaScript for the app, plus Jasmine JavaScript files and Java
-libraries for the test stack. These will let you run the tutorial app and tests, without requiring
-knowledge of Git. You can download and install the snapshot files as follows:
-
-1. Check to be sure you have all of the <a href="#PreReqs">prerequisites</a> on your system.
-
-1. Navigate to [*the angular server*].
-
-1. Download and unzip [*the snapshot file*] to a suitable location.
-
-1. Change directories to [*install-dir*]/sandbox.
-
-1. Run the following command:
- * `./goto_step.sh 0`
-
- You have to start out at the beginning, which is Step 0. After you set up Step 0, you can skip
- around between any steps.
-
-1. To see the app running in your browser, do the following:
- * __For node.js users:__
- 1. Run `./scripts/web-server.js` to run the web server.
- 1. Open a browser window for the app and navigate to http://localhost:8000/app/index.html.
- 1. Open a browser window for the tests, navigate to http://localhost:9876, and choose
- "strict mode".
-
- * __For other http servers:__
- 1. Configure servers to serve the app and test files in the [*install-dir*]/sandbox.
- 1. Start the server.
- 1. Navigate in your app browser to
- http://localhost:[*port-number*]/[*context-path*]/app/index.html.
- 1. Navigate in your test browser to http://localhost:[*port-number*] and choose "strict
- mode".
-
-1. To view the tutorial app at different steps, run `./goto_step.sh [0-11]` and then refresh your
-browser. For example, say you're on Step 5 of the tutorial, and you want to see the app in action:
-
- 1. Run `goto_step.sh 5` from the command line in the `sandbox` directory.
- 1. Refresh your app browser.
-
-<a name="ReadingExamples"></a>
-# Reading the Examples
-
-If you don't want to set up anything on your local machine, you can read through {@link Tutorial
-the tutorial} and inspect the tutorial files on our servers; doing this will give you a good idea
-of what angular does.
-
-To see the running app at each tutorial step, click the "Example" link at the top or bottom of
-each tutorial page.
-
-To view the code differences between tutorial steps, click the Code Diff link at top or bottom of
-each tutorial page. Additions are highlighted in green; deletions are highlighted in red.
-
-
-# Relative URLs
-Throughout the tutorial, we use relative URLs to refer to files hosted on our local http server.
-The absolute URL depends on your configuration. For example, if you are using the node.js server,
-`app/index.html` translates to:
-
- http://localhost:8000/app/index.html
-
-If you are using your own http server running on port 8080 and the tutorial files are hosted at
-`/angular_tutorial`, `app/index.html` translates to:
-
- http://localhost:8080/angular_tutorial/app/index.html