aboutsummaryrefslogtreecommitdiffstats
path: root/docs/content/tutorial
diff options
context:
space:
mode:
authorMisko Hevery2011-04-29 15:18:27 -0700
committerIgor Minar2011-06-06 22:28:38 -0700
commit11e9572b952e49b01035e956c412d6095533031a (patch)
tree04dbf96802f552693d44c541c0d825a2769e3d57 /docs/content/tutorial
parentb6bc6c2ddf1ae1523ec7e4cb92db209cd6501181 (diff)
downloadangular.js-11e9572b952e49b01035e956c412d6095533031a.tar.bz2
Move documentation under individual headings
Diffstat (limited to 'docs/content/tutorial')
-rw-r--r--docs/content/tutorial/index.ngdoc172
-rwxr-xr-xdocs/content/tutorial/step_00.ngdoc77
-rwxr-xr-xdocs/content/tutorial/step_01.ngdoc88
-rwxr-xr-xdocs/content/tutorial/step_02.ngdoc137
-rwxr-xr-xdocs/content/tutorial/step_03.ngdoc108
-rwxr-xr-xdocs/content/tutorial/step_04.ngdoc161
-rwxr-xr-xdocs/content/tutorial/step_05.ngdoc147
-rwxr-xr-xdocs/content/tutorial/step_06.ngdoc113
-rwxr-xr-xdocs/content/tutorial/step_07.ngdoc181
-rwxr-xr-xdocs/content/tutorial/step_08.ngdoc148
-rwxr-xr-xdocs/content/tutorial/step_09.ngdoc108
-rw-r--r--docs/content/tutorial/step_10.ngdoc110
-rw-r--r--docs/content/tutorial/step_11.ngdoc178
13 files changed, 1728 insertions, 0 deletions
diff --git a/docs/content/tutorial/index.ngdoc b/docs/content/tutorial/index.ngdoc
new file mode 100644
index 00000000..b430b248
--- /dev/null
+++ b/docs/content/tutorial/index.ngdoc
@@ -0,0 +1,172 @@
+@workInProgress
+@ngdoc overview
+@name Tutorial
+@description
+
+A great way to get introduced to angular is to work through the {@link tutorial.step_00 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/content/tutorial/step_00.ngdoc b/docs/content/tutorial/step_00.ngdoc
new file mode 100755
index 00000000..e506fcaf
--- /dev/null
+++ b/docs/content/tutorial/step_00.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_01 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_01 Next}</td>
+</tr>
+</table>
diff --git a/docs/content/tutorial/step_01.ngdoc b/docs/content/tutorial/step_01.ngdoc
new file mode 100755
index 00000000..e22adc20
--- /dev/null
+++ b/docs/content/tutorial/step_01.ngdoc
@@ -0,0 +1,88 @@
+@workInProgress
+@ngdoc overview
+@name Tutorial: Step 1
+@description
+<table id="tutorial_nav">
+ <tr>
+ <td id="previous_step">{@link tutorial.step_00 Previous}</td>
+ <td id="step_result">{@link http://angular.github.com/angular-phonecat/step-1/app Example}</td>
+ <td id="tut_home">{@link tutorial Tutorial Home}</td>
+ <td id="code_diff">
+{@link https://github.com/angular/angular-phonecat/compare/step-0...step-1 Code Diff}</td>
+ <td id="next_step">{@link tutorial.step_02 Next}</td>
+ </tr>
+</table>
+
+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
+example:
+
+ ...
+ <html xmlns:ng="http://angularjs.org">
+ ...
+
+Let's add the following code to `index.html`:
+
+__`app/index.html`:__
+<pre>
+<head>
+...
+ <title>Google Phone Gallery</title>
+...
+</head>
+...
+ <ul>
+ <li>
+ <span>Nexus S<span>
+ <p>
+ Fast just got faster with Nexus S.
+ </p>
+ </li>
+ <li>
+ <span>Motorola XOOM™ with Wi-Fi<span>
+ <p>
+ The Next, Next Generation tablet.
+ </p>
+ </li>
+ </ul>
+...
+</pre>
+
+## Discussion:
+
+* It's a static web page! We displayed info about two phones! Yay.
+
+* 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 Using Git:}__
+
+ From your `angular-phonecat` directory, run this command:
+
+ git checkout step-1
+
+ * __{@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.
+
+<table id="tutorial_nav">
+ <tr>
+ <td id="previous_step">{@link tutorial.step_00 Previous}</td>
+ <td id="step_result">{@link http://angular.github.com/angular-phonecat/step-1/app Example}</td>
+ <td id="tut_home">{@link tutorial Tutorial Home}</td>
+ <td id="code_diff">
+{@link https://github.com/angular/angular-phonecat/compare/step-0...step-1 Code Diff}</td>
+ <td id="next_step">{@link tutorial.step_02 Next}</td>
+ </tr>
+</table>
diff --git a/docs/content/tutorial/step_02.ngdoc b/docs/content/tutorial/step_02.ngdoc
new file mode 100755
index 00000000..50fbd240
--- /dev/null
+++ b/docs/content/tutorial/step_02.ngdoc
@@ -0,0 +1,137 @@
+@workInProgress
+@ngdoc overview
+@name Tutorial: Step 2
+@description
+<table id="tutorial_nav">
+ <tr>
+ <td id="previous_step">{@link tutorial.step_01 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/compare/step-1...step-2 Code
+Diff}</td>
+ <td id="next_step">{@link tutorial.step_03 Next}</td>
+ </tr>
+</table>
+
+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:
+
+__`app/index.html`:__
+<pre>
+...
+<body ng:controller="PhoneListCtrl">
+
+ <ul>
+ <li ng:repeat="phone in phones">
+ {{phone.name}}
+ <p>{{phone.snippet}}</p>
+ </li>
+ </ul>
+
+ <script src="lib/angular/angular.js" ng:autobind></script>
+ <script src="js/controllers.js"></script>
+</body>
+...
+</pre>
+
+Our data __Model__ (a short list of phones in object literal notation) is instantiated within our
+__Controller__ function (`PhoneListCtrl`):
+
+__`app/js/controllers.js`:__
+<pre>
+/* App Controllers */
+
+function PhoneListCtrl() {
+ this.phones = [{"name": "Nexus S",
+ "snippet": "Fast just got faster with Nexus S."},
+ {"name": "Motorola XOOM™ with Wi-Fi",
+ "snippet": "The Next, Next Generation tablet."},
+ {"name": "MOTOROLA XOOM™",
+ "snippet": "The Next, Next Generation tablet."}];
+}
+</pre>
+
+The "Angular way" urges us to test as we develop:
+
+__`test/unit/controllersSpec.js`:__
+<pre>
+/* jasmine specs for controllers go here */
+describe('PhoneCat controllers', function() {
+
+ describe('PhoneListCtrl', function(){
+
+ it('should create "phones" model with 3 phones', function() {
+ var ctrl = new PhoneListCtrl();
+ expect(ctrl.phones.length).toBe(3);
+ });
+ });
+});
+</pre>
+
+## Discussion:
+
+So what were our changes from Step 1?
+
+* __View template:__ We replaced the hard-coded phone list with the {@link
+angular.widget.@ng:repeat ng:repeat widget} and two {@link guide.expression angular expressions}
+enclosed in curly braces: `{{phone.name}}` and `{{phone.snippet}}`:
+
+ * The `ng:repeat="phone in phones"` statement in the `<li>` tag is an angular repeater. It
+ tells angular to create a `<li>` element for each phone in the phones list, using the first
+ `<li>` tag as the template.
+
+ * 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 creates
+ data-binding between the View and the Model. In angular, the View is a projection of the Model
+ 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 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
+ (`PhoneListCtrl`).
+ * We instantiated our data within the scope of our controller function, and our template
+ binding points are located within the block bounded by the `<body
+ ng:controller="PhoneListCtrl>` tag.
+
+ 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.
+
+* __Model:__ For our data model, we created a simple array of phone records, specified in object
+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 3 records in the phones array.
+
+ 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_01 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/compare/step-1...step-2 Code
+Diff}</td>
+ <td id="next_step">{@link tutorial.step_03 Next}</td>
+ </tr>
+</table>
diff --git a/docs/content/tutorial/step_03.ngdoc b/docs/content/tutorial/step_03.ngdoc
new file mode 100755
index 00000000..4333636d
--- /dev/null
+++ b/docs/content/tutorial/step_03.ngdoc
@@ -0,0 +1,108 @@
+@workInProgress
+@ngdoc overview
+@name Tutorial: Step 3
+@description
+<table id="tutorial_nav">
+<tr>
+ <td id="previous_step">{@link tutorial.step_02 Previous}</td>
+ <td id="step_result">{@link http://angular.github.com/angular-phonecat/step-3/app Example}</td>
+ <td id="tut_home">{@link tutorial Tutorial Home}</td>
+ <td id="code_diff">{@link
+ https://github.com/angular/angular-phonecat/commit/a03815f8fb00217f5f9c1d3ef83282f79818e706 Code
+ Diff}</td>
+ <td id="next_step">{@link tutorial.step_04 Next}</td>
+</tr>
+</table>
+
+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>
+...
+ Fulltext Search: <input name="query"/>
+
+ <ul class="phones">
+ <li ng:repeat="phone in phones.$filter(query)">
+ {{phone.name}}
+ <p>{{phone.snippet}}</p>
+ </li>
+ </ul>
+...
+</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);
+ });
+ });
+});
+</pre>
+
+## Discussion:
+
+We continued using the same controller that we set up in Step 2, but we added the following
+features to our app:
+
+* __Search Box:__ A standard HTML `<input>` tag combined with angular's {@link
+angular.Array.filter $filter} utility (added to the repeater) lets a user type in search criteria
+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 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.
+
+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.
+
+ * 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:__ 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.
+
+ * How easy it is to write end-to-end tests. This is just a simple test, but the point here is
+ to show how easy it is to set up a functional, readable, end-to-end test.
+
+<table id="tutorial_nav">
+<tr>
+ <td id="previous_step">{@link tutorial.step_02 Previous}</td>
+ <td id="step_result">{@link http://angular.github.com/angular-phonecat/step-3/app Example}</td>
+ <td id="tut_home">{@link tutorial Tutorial Home}</td>
+ <td id="code_diff">{@link
+ https://github.com/angular/angular-phonecat/commit/a03815f8fb00217f5f9c1d3ef83282f79818e706 Code
+ Diff}</td>
+ <td id="next_step">{@link tutorial.step_04 Next}</td>
+</tr>
+</table>
diff --git a/docs/content/tutorial/step_04.ngdoc b/docs/content/tutorial/step_04.ngdoc
new file mode 100755
index 00000000..0589ba75
--- /dev/null
+++ b/docs/content/tutorial/step_04.ngdoc
@@ -0,0 +1,161 @@
+@workInProgress
+@ngdoc overview
+@name Tutorial: Step 4
+@description
+<table id="tutorial_nav">
+<tr>
+<td id="previous_step">{@link tutorial.step_03 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/compare/step-3...step-4 Code
+Diff}</td>
+<td id="next_step">{@link tutorial.step_05 Next}</td>
+</tr>
+</table>
+
+In this step, we add a feature that lets our users choose which way to order the phone list.
+
+__`app/index.html`:__
+<pre>
+...
+ <ul class="predicates">
+ <li>
+ Search: <input type="text" name="query"/>
+ </li>
+ <li>
+ Sort by:
+ <select name="orderProp">
+ <option value="name">Alphabetical</option>
+ <option value="age">Newest</option>
+ </select>
+ </li>
+ </ul>
+
+ <ul class="phones">
+ <li ng:repeat="phone in phones.$filter(query).$orderBy(orderProp)">
+ {{phone.name}}
+ <p>{{phone.snippet}}</p>
+ </li>
+ </ul>
+...
+</pre>
+
+__`app/js/controller.js`:__
+<pre>
+/* App Controllers */
+
+function PhoneListCtrl() {
+ this.phones = [{"name": "Nexus S",
+ "snippet": "Fast just got faster with Nexus S.",
+ "age": 0},
+ {"name": "Motorola XOOM™ with Wi-Fi",
+ "snippet": "The Next, Next Generation tablet.",
+ "age": 1},
+ {"name": "MOTOROLA XOOM™",
+ "snippet": "The Next, Next Generation tablet.",
+ "age": 2}];
+
+ this.orderProp = 'age';
+}
+</pre>
+
+__`test/unit/controllerSpec.js`:__
+<pre>
+/* jasmine specs for controllers go here */
+describe('PhoneCat controllers', function() {
+
+ describe('PhoneListCtrl', function(){
+ var scope, $browser, ctrl;
+
+ beforeEach(function() {
+ ctrl = new PhoneListCtrl();
+ });
+
+
+ it('should create "phones" model with 3 phones', function() {
+ expect(ctrl.phones.length).toBe(3);
+ });
+
+
+ it('should set the default value of orderProp model', function() {
+ expect(ctrl.orderProp).toBe('age');
+ });
+ });
+});
+</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`. 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">
+<tr>
+<td id="previous_step">{@link tutorial.step_03 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/compare/step-3...step-4 Code
+Diff}</td>
+<td id="next_step">{@link tutorial.step_05 Next}</td>
+</tr>
+</table>
diff --git a/docs/content/tutorial/step_05.ngdoc b/docs/content/tutorial/step_05.ngdoc
new file mode 100755
index 00000000..8ec0fca4
--- /dev/null
+++ b/docs/content/tutorial/step_05.ngdoc
@@ -0,0 +1,147 @@
+@workInProgress
+@ngdoc overview
+@name Tutorial: Step 5
+@description
+<table id="tutorial_nav">
+<tr>
+ <td id="previous_step">{@link tutorial.step_04 Previous}</td>
+ <td id="step_result">{@link http://angular.github.com/angular-phonecat/step-5/app Example}</td>
+ <td id="tut_home">{@link tutorial Tutorial Home}</td>
+<td id="code_diff">{@link https://github.com/angular/angular-phonecat/compare/step-4...step-5 Code
+Diff}</td>
+ <td id="next_step">{@link tutorial.step_06 Next}</td>
+</tr>
+</table>
+
+In this step, the View template remains the same but the Model and Controller change. We'll
+introduce the use of an angular {@link angular.service service}, which we will use to implement an
+`XMLHttpRequest` request to communicate with a server. Angular provides the built-in {@link
+angular.service.$xhr $xhr} service to make this easy.
+
+The addition of the `$xhr` service to our app gives us the opportunity to talk about {@link
+guide.di Dependency Injection} (DI). The use of DI is another cornerstone of the angular
+philosophy. DI helps make your web apps well structured, loosely coupled, and ultimately easier to
+test.
+
+__`app/js/controllers.js:`__
+<pre>
+/* App Controllers */
+
+function PhoneListCtrl($xhr) {
+ var self = this;
+
+ $xhr('GET', 'phones/phones.json', function(code, response) {
+ self.phones = response;
+ });
+
+ self.orderProp = 'age';
+}
+
+//PhoneListCtrl.$inject = ['$xhr'];
+</pre>
+
+__`test/unit/controllerSpec.js`:__
+<pre>
+/* jasmine specs for controllers go here */
+describe('PhoneCat controllers', function() {
+
+ describe('PhoneListCtrl', function(){
+ var scope, $browser, ctrl;
+
+ beforeEach(function() {
+ scope = angular.scope();
+ $browser = scope.$service('$browser');
+
+ $browser.xhr.expectGET('phones/phones.json').respond([{name: 'Nexus S'},
+ {name: 'Motorola DROID'}]);
+ ctrl = scope.$new(PhoneListCtrl);
+ });
+
+
+ it('should create "phones" model with 2 phones fetched from xhr', function() {
+ expect(ctrl.phones).toBeUndefined();
+ $browser.xhr.flush();
+
+ expect(ctrl.phones).toEqual([{name: 'Nexus S'},
+ {name: 'Motorola DROID'}]);
+ });
+
+
+ it('should set the default value of orderProp model', function() {
+ expect(ctrl.orderProp).toBe('age');
+ });
+ });
+});
+</pre>
+
+## Discussion:
+
+* __Services:__ {@link angular.service Services} are substitutable objects managed by angular's
+{@link guide.di DI subsystem}. Angular services simplify some of the standard operations common
+to web apps. Angular provides several built-in services (such as {@link angular.service.$xhr
+$xhr}). You can also create your own custom services.
+
+* __Dependency Injection:__ To use an angular service, you simply provide the name of the service
+as an argument to the controller's constructor function. The name of the argument is significant,
+because angular's {@link guide.di DI subsystem} recognizes the identity of a service by its name,
+and provides the name of the service to the controller during the controller's construction. The
+dependency injector also takes care of creating any transitive dependencies the service may have
+(services often depend upon other services).
+
+ Note: if you minify the javascript code for this controller, all function arguments will be
+ minified as well. This will result in the dependency injector not being able to identify
+ services correctly. To overcome this issue, just assign an array with service identifier strings
+ into the `$inject` property of the controller function.
+
+* __`$xhr`:__ We moved our data set out of the controller and into the file
+`app/phones/phones.json` (and added some more phones). We used the `$xhr` service to make a GET
+HTTP request to our web server, asking for `phone/phones.json` (the url is relative to our
+`index.html` file). The server responds with the contents of the json file, which serves as the
+source of our data. Keep in mind that the response might just as well have been dynamically
+generated by a sophisticated backend server. To our web server they both look the same, but using
+a real backend server to generate a response would make our tutorial unnecessarily complicated.
+
+ Notice that the $xhr service takes a callback as the last parameter. This callback is used to
+ process the response. In our case, we just assign the response to the current scope controlled
+ by the controller, as a model called `phones`. Have you realized that we didn't even have to
+ parse the response? Angular took care of that for us.
+
+* __Testing:__ The unit tests have been expanded. Because of the dependency injection business,
+we now need to create the controller the same way that angular does it behind the scenes. For this
+reason, we need to:
+
+ * Create a root scope object by calling `angular.scope()`
+
+ * Call `scope.$new(PhoneListCtrl)` to get angular to create the child scope associated with
+ our controller.
+
+ At the same time, we need to tell the testing harness that it should expect an incoming
+ request from our controller. To do this we:
+
+ * Use the `$service` method to retrieve the `$browser` service - this is a service that in
+ angular represents various browser APIs. In tests, angular automatically uses a mock version
+ of this service that allows you to write tests without having to deal with these native APIs
+ and the global state associated with them.
+
+ * We use the `$browser.expectGET` method to train the `$browser` object to expect an incoming
+ http request and tell it what to respond with. Note that the responses are not returned before
+ we call the `$browser.xhr.flush()` method.
+
+ * We then make assertions to verify that the `phones` model doesn't exist on the scope, before
+ the response is received.
+
+ * We flush the xhr queue in the browser by calling `$browser.xhr.flush()`. This causes the
+ callback we passed into the `$xhr` service to be executed with the trained response.
+
+ * Finally, we make the assertions, verifying that the phone model now exists on the scope.
+
+<table id="tutorial_nav">
+<tr>
+ <td id="previous_step">{@link tutorial.step_04 Previous}</td>
+ <td id="step_result">{@link http://angular.github.com/angular-phonecat/step-5/app Example}</td>
+ <td id="tut_home">{@link tutorial Tutorial Home}</td>
+ <td id="code_diff">{@link https://github.com/angular/angular-phonecat/compare/step-4...step-5
+ Code Diff}</td>
+ <td id="next_step">{@link tutorial.step_06 Next}</td>
+</tr>
+</table>
diff --git a/docs/content/tutorial/step_06.ngdoc b/docs/content/tutorial/step_06.ngdoc
new file mode 100755
index 00000000..afe809a6
--- /dev/null
+++ b/docs/content/tutorial/step_06.ngdoc
@@ -0,0 +1,113 @@
+@workInProgress
+@ngdoc overview
+@name Tutorial: Step 6
+@description
+<table id="tutorial_nav">
+<tr>
+<td id="previous_step">{@link tutorial.step_05 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/compare/step-5...step-6 Code
+Diff}</td>
+<td id="next_step">{@link tutorial.step_07 Next}</td>
+</tr>
+</table>
+
+In this step, we add thumbnail images, links, and a little more CSS to our app. For now, our
+links go nowhere. One step at a time; in the next step we'll implement new views that these links
+will open.
+
+__`app/index.html`:__
+<pre>
+...
+ <ul class="predicates">
+ <li>
+ Search: <input type="text" name="query"/>
+ </li>
+ <li>
+ Sort by:
+ <select name="orderProp">
+ <option value="name">Alphabetical</option>
+ <option value="age">Newest</option>
+ </select>
+ </li>
+ </ul>
+
+ <ul class="phones">
+ <li ng:repeat="phone in phones.$filter(query).$orderBy(orderProp)">
+ <a href="#/phones/{{phone.id}}">{{phone.name}}</a>
+ <a href="#/phones/{{phone.id}}" class="thumb"><img ng:src="{{phone.imageUrl}}"></a>
+ <p>{{phone.snippet}}</p>
+ </li>
+ </ul>
+...
+</pre>
+
+__`app/js/controller.js`__ (Unchanged):
+<pre>
+/* App Controllers */
+
+function PhoneListCtrl($xhr) {
+ var self = this;
+
+ $xhr('GET', 'phones/phones.json', function(code, response) {
+ self.phones = response;
+ });
+
+ self.orderProp = 'age';
+}
+
+//PhoneListCtrl.$inject = ['$xhr'];
+</pre>
+
+__`app/phones/phones.json`__ (sample snippet):
+<pre>
+ [
+ {
+ "age": 4,
+ ...
+ "carrier": "T-Mobile",
+ "id": "motorola-defy-with-motoblur",
+ "imageUrl": "http://google.com/phone/image/small/640001",
+ "name": "Motorola DEFY\u2122 with MOTOBLUR\u2122",
+ "snippet": "Are you ready for everything life throws your way?"
+ },
+ …
+ ]
+</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
+{@link angular.markup double-curly brace markup} in the href attribute values. These represent
+attribute bindings, and work the same way as the bindings we saw in previous steps.
+
+* Note also the use of the {@link angular.directive.ng:src ng:src} directive in the `<img>` tag.
+That directive prevents the browser from treating the angular `{{ exppression }}` markup
+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_05 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/compare/step-5...step-6 Code
+Diff}</td>
+<td id="next_step">{@link tutorial.step_07 Next}</td>
+</tr>
+</table>
diff --git a/docs/content/tutorial/step_07.ngdoc b/docs/content/tutorial/step_07.ngdoc
new file mode 100755
index 00000000..802130c5
--- /dev/null
+++ b/docs/content/tutorial/step_07.ngdoc
@@ -0,0 +1,181 @@
+@workInProgress
+@ngdoc overview
+@name Tutorial: Step 7
+@description
+<table id="tutorial_nav">
+<tr>
+<td id="previous_step">{@link tutorial.step_06 Previous}</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/compare/step-6...step-7 Code
+Diff}</td>
+<td id="next_step">{@link tutorial.step_08 Next}</td>
+</tr>
+</table>
+
+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.
+
+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.
+
+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.
+
+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">
+
+ <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`:__
+<pre>
+<ul class="predicates">
+ <li>
+ Search: <input type="text" name="query"/>
+ </li>
+ <li>
+ Sort by:
+ <select name="orderProp">
+ <option value="name">Alphabetical</option>
+ <option value="age">Newest</option>
+ </select>
+ </li>
+</ul>
+
+<ul class="phones">
+ <li ng:repeat="phone in phones.$filter(query).$orderBy(orderProp)">
+ <a href="#/phones/{{phone.id}}">{{phone.name}}</a>
+ <a href="#/phones/{{phone.id}}" class="thumb"><img ng:src="{{phone.imageUrl}}"></a>
+ <p>{{phone.snippet}}</p>
+ </li>
+</ul>
+</pre>
+
+__`app/partials/phone-list.html`:__
+<pre>
+TBD: detail view for {{params.phoneId}}
+</pre>
+
+__`app/js/controller.js`:__
+<pre>
+/* App Controllers */
+
+function PhoneCatCtrl($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);
+}
+
+//PhoneCatCtrl.$inject = ['$route'];
+
+
+function PhoneListCtrl($xhr) {
+ var self = this;
+
+ $xhr('GET', 'phones/phones.json', function(code, response) {
+ self.phones = response;
+ });
+
+ self.orderProp = 'age';
+}
+
+//PhoneListCtrl.$inject = ['$xhr'];
+
+
+function PhoneDetailCtrl() {}
+</pre>
+
+## Discussion:
+
+* __The View.__ Our View template in `index.html` has been reduced down to this:
+`<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. 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 placeholder template for now).
+
+* __The Controller(s).__ We now have a new root controller (`PhoneCatCtrl`) and two
+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` 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
+ `: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`.
+
+ * __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_06 Previous}</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/compare/step-6...step-7 Code
+Diff}</td>
+<td id="next_step">{@link tutorial.step_08 Next}</td>
+</tr>
+</table>
diff --git a/docs/content/tutorial/step_08.ngdoc b/docs/content/tutorial/step_08.ngdoc
new file mode 100755
index 00000000..65ce6883
--- /dev/null
+++ b/docs/content/tutorial/step_08.ngdoc
@@ -0,0 +1,148 @@
+@workInProgress
+@ngdoc overview
+@name Tutorial: Step 8
+@description
+<table id="tutorial_nav">
+<tr>
+<td id="previous_step">{@link tutorial.step_07 Previous}</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/compare/step-7...step-8 Code
+Diff}</td>
+<td id="next_step">{@link tutorial.step_09 Next}</td>
+</tr>
+</table>
+
+In this step, we implement the Phone Details View template. Once again we will use {@link
+angular.services.$xhr $xhr} to fetch our data, and we'll flesh out the `phone-details.html` View
+template.
+
+__`app/partials/phone-details.html`:__
+<pre>
+<img ng:src="{{phone.images[0]}}" class="phone"/>
+
+<h1>{{phone.name}}</h1>
+
+<p>{{phone.description}}</p>
+
+<ul class="phone-thumbs">
+ <li ng:repeat="img in phone.images">
+ <img ng:src="{{img}}"/>
+ </li>
+</ul>
+
+<ul class="specs">
+ <li>
+ <span>Availability and Networks</span>
+ <dl>
+ <dt>Availability</dt>
+ <dd ng:repeat="availability in phone.availability">{{availability}}</dd>
+ </dl>
+ </li>
+ ...
+ </li>
+ <span>Additional Features</span>
+ <dd>{{phone.additionalFeatures}}</dd>
+ </li>
+</ul>
+</pre>
+
+__`app/js/controller.js`:__
+<pre>
+function PhoneCatCtrl($route) (same as Step 7)
+
+function PhoneListCtrl($xhr) (same as Step 7)
+
+function PhoneDetailCtrl($xhr) {
+ var self = this;
+
+ $xhr('GET', 'phones/' + self.params.phoneId + '.json', function(code, response) {
+ self.phone = response;
+ });
+}
+
+//PhoneDetailCtrl.$inject = ['$xhr'];
+</pre>
+
+__`app/phones/nexus-s.json`:__ (sample snippet)
+<pre>
+{
+ "additionalFeatures": "Contour Display, Near Field Communications (NFC), Three-axis gyroscope,
+ Anti-fingerprint display coating, Internet Calling support (VoIP/SIP)",
+ "android": {
+ "os": "Android 2.3",
+ "ui": "Android"
+ },
+ ...
+ "images": [
+ "img/phones/nexus-s.0.jpg",
+ "img/phones/nexus-s.1.jpg",
+ "img/phones/nexus-s.2.jpg",
+ "img/phones/nexus-s.3.jpg"
+ ],
+ "storage": {
+ "flash": "16384MB",
+ "ram": "512MB"
+ }
+}
+</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 into the
+view.
+
+* Note how we used the `$route` `params` object from the scope managed by the root controller
+(`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_07 Previous}</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/compare/step-7...step-8 Code
+Diff}</td>
+<td id="next_step">{@link tutorial.step_09 Next}</td>
+</tr>
+</table>
diff --git a/docs/content/tutorial/step_09.ngdoc b/docs/content/tutorial/step_09.ngdoc
new file mode 100755
index 00000000..2d6ed925
--- /dev/null
+++ b/docs/content/tutorial/step_09.ngdoc
@@ -0,0 +1,108 @@
+@workInProgress
+@ngdoc overview
+@name Tutorial: Step 9
+@description
+<table id="tutorial_nav">
+<tr>
+<td id="previous_step">{@link tutorial.step_08 Previous}</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/compare/step-8...step-9 Code
+Diff}</td>
+<td id="next_step">{@link tutorial.step_10 Next}</td>
+</tr>
+</table>
+
+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.) 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 glyphs: ✓ for "true", and ✘ for "false".
+
+Our filter code lives in `app/js/filters.js`:
+
+__`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>
+
+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`:__
+<pre>
+<img ng:src="{{phone.images[0].large}}" class="phone"/>
+<h1>{{phone.name}}</h1>
+<p>{{phone.description}}</p>
+...
+<ul class="specs">
+ ...
+ <li>
+ <span>Connectivity</span>
+ <dl>
+ <dt>Network Support</dt>
+ <dd>{{phone.connectivity.cell}}</dd>
+ <dt>WiFi</dt>
+ <dd>{{phone.connectivity.wifi}}</dd>
+ <dt>Bluetooth</dt>
+ <dd>{{phone.connectivity.bluetooth}}</dd>
+ <dt>Infrared</dt>
+ <dd>{{phone.connectivity.infrared | checkmark}}</dd>
+ <dt>GPS</dt>
+ <dd>{{phone.connectivity.gps | checkmark}}</dd>
+ </dl>
+ </li>
+...
+</ul>
+</pre>
+
+__`app/js/filters.js`:__ (New)
+<pre>
+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
+the "Writing your own Filters" section of the {@link angular.filter angular.filter} page, you
+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
+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_08 Previous}</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/compare/step-8...step-9 Code
+Diff}</td>
+<td id="next_step">{@link tutorial.step_10 Next}</td>
+</tr>
+</table>
diff --git a/docs/content/tutorial/step_10.ngdoc b/docs/content/tutorial/step_10.ngdoc
new file mode 100644
index 00000000..130b4023
--- /dev/null
+++ b/docs/content/tutorial/step_10.ngdoc
@@ -0,0 +1,110 @@
+@workInProgress
+@ngdoc overview
+@name Tutorial: Step 10
+@description
+<table id="tutorial_nav">
+<tr>
+<td id="previous_step">{@link tutorial.step_09 Previous}</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/compare/step-9...step-10
+Code Diff}</td>
+<td id="next_step">{@link tutorial.step_11 Next}</td>
+</tr>
+</table>
+
+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`:__
+<pre>
+<img ng:src="{{mainImageUrl}}" class="phone"/>
+
+<h1>{{phone.name}}</h1>
+
+<p>{{phone.description}}</p>
+
+<ul class="phone-thumbs">
+ <li ng:repeat="img in phone.images">
+ <img ng:src="{{img}}" ng:click="setImage(img)">
+ </li>
+</ul>
+...
+</pre>
+
+__`app/js/controllers.js`:__
+<pre>
+...
+function PhoneDetailCtrl($xhr) {
+ var self = this;
+
+ $xhr('GET', 'phones/' + self.params.phoneId + '.json', function(code, response) {
+ self.phone = response;
+ self.mainImageUrl = response.images[0];
+ });
+
+ self.setImage = function(imageUrl) {
+ self.mainImageUrl = imageUrl;
+ }
+}
+
+//PhoneDetailCtrl.$inject = ['$xhr'];
+</pre>
+
+__`test/e2e/scenarios.js`:__
+<pre>
+/* jasmine-like end2end tests go here */
+...
+ 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');
+ });
+
+ 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');
+ });
+
+
+ it('should swap main image if a thumbnail image is clicked on', function() {
+ element('.phone-thumbs li:nth-child(3) img').click();
+ expect(element('img.phone').attr('src')).toBe('img/phones/nexus-s.2.jpg');
+
+ element('.phone-thumbs li:nth-child(1) img').click();
+ expect(element('img.phone').attr('src')).toBe('img/phones/nexus-s.0.jpg');
+ });
+ });
+});
+</pre>
+
+## Discussion:
+
+Adding the phone image swapping feature is fairly straightforward:
+
+* 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
+the user.
+* 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_09 Previous}</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/compare/step-9...step-10
+Code Diff}</td>
+<td id="next_step">{@link tutorial.step_11 Next}</td>
+</tr>
+</table>
diff --git a/docs/content/tutorial/step_11.ngdoc b/docs/content/tutorial/step_11.ngdoc
new file mode 100644
index 00000000..e383f406
--- /dev/null
+++ b/docs/content/tutorial/step_11.ngdoc
@@ -0,0 +1,178 @@
+@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>