aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/content/tutorial/index.ngdoc47
-rwxr-xr-xdocs/content/tutorial/step_00.ngdoc19
-rwxr-xr-xdocs/content/tutorial/step_01.ngdoc17
-rwxr-xr-xdocs/content/tutorial/step_02.ngdoc80
-rwxr-xr-xdocs/content/tutorial/step_03.ngdoc59
-rwxr-xr-xdocs/content/tutorial/step_04.ngdoc49
-rwxr-xr-xdocs/content/tutorial/step_05.ngdoc65
-rwxr-xr-xdocs/content/tutorial/step_06.ngdoc22
-rwxr-xr-xdocs/content/tutorial/step_07.ngdoc58
-rwxr-xr-xdocs/content/tutorial/step_08.ngdoc43
-rwxr-xr-xdocs/content/tutorial/step_09.ngdoc43
-rw-r--r--docs/content/tutorial/step_10.ngdoc41
-rw-r--r--docs/content/tutorial/step_11.ngdoc38
13 files changed, 379 insertions, 202 deletions
diff --git a/docs/content/tutorial/index.ngdoc b/docs/content/tutorial/index.ngdoc
index efe30573..85c84260 100644
--- a/docs/content/tutorial/index.ngdoc
+++ b/docs/content/tutorial/index.ngdoc
@@ -18,10 +18,10 @@ developing a typical web app. For this tutorial, we modified the angular-seed as
* Removed the example app
* Added phone images to `app/img/phones`
-* Added phone data files (JSON) to `app/phones`
+* Added phone data files (JSON) to `app/phones`
- Note: Using the angular seed app isn't required for building angular apps, but doing so helps
- you get started quickly and makes the development and testing process much easier.
+**Note**: Using the angular seed app isn't required for building angular apps, but doing so helps
+you get started quickly and makes the development and testing process much easier.
When you finish the tutorial you will be able to:
@@ -46,36 +46,38 @@ To run the tutorial app and tests on your machine you will need the following:
* A Mac or Linux machine (required by the tutorial scripts, not angular)
* 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 only required for if you want to run tests via JsTestDriver.
+`node.js` ({@link https://github.com/joyent/node/wiki/Installation node.js install guide}) or
+another http sever (such as Apache, etc.).
+* Java. This is required for running tests with JsTestDriver.
* A web browser.
* A text editor.
-# Using Git
-The following instructions are for developers who are comfortable with Git versioning system:
+# Working with the code
+
+There are two ways that you can you follow this tutorial and hack on the code:
+
+## Using Git
+
+The following instructions are for developers who are comfortable with the Git 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:
+https://github.com/angular/angular-phonecat GitHub} by running the following command in a terminal:
- git clone git://github.com/angular/angular-phonecat.git
+ git clone git://github.com/angular/angular-phonecat.git
This will create a directory called `angular-phonecat` in the current directory.
3. Change your current directory to `angular-phonecat`.
- cd angular-phonecat
+ cd angular-phonecat
The tutorial instructions assume you are running all commands from this directory.
-Read the Tutorial Navigation section, then navigate to Step 0.
-
-# Using Snapshots
+## 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
@@ -84,18 +86,21 @@ 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*], download and then unzip [*the snapshot file*] to an
-[*install-dir*].
+2. {@link TODO Download the zip archive} with all files and unzip them into `[tutorial-dir]`
+directory.
-3. Change directories to [*install-dir*]/sandbox.
- cd [*install-dir*]/sandbox
+3. Change directories to `[tutorial-dir]/sandbox`.
+
+ cd [tutorial-dir]/sandbox
-Read the Tutorial Navigation section, then navigate to step-0.
# Tutorial Navigation
To see the app running on the angular server, click the "Live Demo" link at the top or bottom of
any tutorial page. To view the code differences between tutorial steps, click the Code Diff link
at top or bottom of each tutorial page. In the Code Diff, additions are highlighted in green;
-deletions are highlighted in red.
+deletions are highlighted in red.
+
+
+Let's get going and proceed to {@link tutorial/step_00 step 0}.
diff --git a/docs/content/tutorial/step_00.ngdoc b/docs/content/tutorial/step_00.ngdoc
index a6dc1ca9..b03d2ec6 100755
--- a/docs/content/tutorial/step_00.ngdoc
+++ b/docs/content/tutorial/step_00.ngdoc
@@ -8,13 +8,13 @@
<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-0/app Live Demo}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
<td id="code_diff">Code Diff</td>
-<td id="next_step">{@link tutorial.step_0 Next}</td>
+<td id="next_step">{@link tutorial.step_01 Next}</td>
</tr>
</table>
You are now ready to build the phone cat application. In this step, you will become familiar with
-the most important source code files, learn how to start the web services, and run the application
-in the browser.
+the most important source code files, learn how to start the development servers bundled with
+angular-seed, and run the application in the browser.
1. Do one of the following:
@@ -22,11 +22,11 @@ in the browser.
git checkout step-0
- * Snapshot users: In the `[install directory]/sandbox` directory, run this command:
+ * Snapshot users: In the `[tutorial-dir]/sandbox` directory, run this command:
./goto_step.sh 0
-This resets your workspace to Step 0 of the tutorial app.
+ This resets your workspace to Step 0 of the tutorial app.
2. To see the app running in a browser, do one of the following:
* __For node.js users:__
@@ -36,8 +36,7 @@ This resets your workspace to Step 0 of the tutorial app.
* __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
+ 2. Navigate in your browser to
http://localhost:[*port-number*]/[*context-path*]/app/index.html.
You can now see the app in the browser. It's not very exciting, but that's OK.
@@ -75,9 +74,11 @@ versions older than 9 (regardless of whether you are using XHTML or HTML).
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.
+angular to bootstrap, compile, and manage the whole html page.
+
+# Summary
-Now let's go to Step 1 and add some content to the web app.
+Now let's go to step 1 and add some content to the web app.
<table id="tutorial_nav">
<tr>
diff --git a/docs/content/tutorial/step_01.ngdoc b/docs/content/tutorial/step_01.ngdoc
index b9c171d2..4f0640c9 100755
--- a/docs/content/tutorial/step_01.ngdoc
+++ b/docs/content/tutorial/step_01.ngdoc
@@ -15,7 +15,7 @@
In this step you will add some basic information about two cell phones to our app.
-1. Do one of the following to reset your workspace to Step 1; be aware that this will throw away
+1. Do one of the following to reset your workspace to step 1; be aware that this will throw away
any changes you might have made to the tutorial files:
* Git users run:
@@ -27,8 +27,8 @@ any changes you might have made to the tutorial files:
./goto_step.sh 1
2. Refresh your browser or check the app out on {@link
-http://angular.github.com/angular-phonecat/step-1/app, our server}. Your page now contains a list
-with information about two phones.
+http://angular.github.com/angular-phonecat/step-1/app anglar's server}. The page now contains a
+list with information about two phones.
The most important changes are listed below. You can see the full diff on {@link
https://github.com/angular/angular-phonecat/compare/step-0...step-1 GitHub}:
@@ -53,7 +53,16 @@ __`app/index.html`:__
...
</pre>
-This addition to your app uses static HTML to display the list. Now, let's go to Step 2 to learn
+# Experiments
+
+* Try adding more static html to `index.html`. For example:
+
+ <p>Total number of phones: 3</p>
+
+
+# Summary
+
+This addition to your app uses static HTML to display the list. Now, let's go to step 2 to learn
how to use angular to dynamically generate the same list.
<table id="tutorial_nav">
diff --git a/docs/content/tutorial/step_02.ngdoc b/docs/content/tutorial/step_02.ngdoc
index 143e310a..fdf881b0 100755
--- a/docs/content/tutorial/step_02.ngdoc
+++ b/docs/content/tutorial/step_02.ngdoc
@@ -21,16 +21,17 @@ of {@link http://en.wikipedia.org/wiki/Model–View–Controller the MVC design
the code and separate concerns. With that in mind, let's use a little angular and JavaScript to
add Model, View, and Controller components to our app.
-1. Reset your workspace to Step 2 using:
+1. Reset your workspace to step 2 using:
- git checkout --force step-2
- or
+ git checkout --force step-2
- ./goto_step.sh 2
+ or
+
+ ./goto_step.sh 2
2. Refresh your browser or check the app out on {@link
-http://angular.github.com/angular-phonecat/step-2/app our server}. The app now contains a list
-with 3 phones.
+http://angular.github.com/angular-phonecat/step-2/app angular's server}. The app now contains a
+list with 3 phones.
The most important changes are listed below. You can see the full diff on {@link
https://github.com/angular/angular-phonecat/compare/step-1...step-2 GitHub}:
@@ -67,9 +68,9 @@ and `{{phone.snippet}}`:
`<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
+ angular.markup angular markup}. The curly markup is shorthand for the angular directive {@link
+ angular.directive.ng:bind ng:bind}. `ng:bind` directives indicates 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.
@@ -102,7 +103,7 @@ data, and logic components:
(`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.
+ 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
@@ -139,26 +140,59 @@ writing tests. Although Jasmine is not required by angular, we used it to write
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}.
-angular-seed project is pre-configured to run all unit tests using {@link
+The angular-seed project is pre-configured to run all unit tests using {@link
http://code.google.com/p/js-test-driver/ JsTestDriver}. To run the test, do the following:
- 1. In a _separate_ terminal window or tab, go to the `angular-phonecat` directory and run
- `./scripts/test-server.sh` to start the test web server.
+1. In a _separate_ terminal window or tab, go to the `angular-phonecat` directory and run
+`./scripts/test-server.sh` to start the test web server.
+
+2. Open a new browser tab or window, navigate to http://localhost:9876, and choose "strict mode".
+At this point, you can leave this tab open and forget about it. JsTestDriver will use it to
+execute our tests and report the results in the terminal.
+
+3. Execute the test by running `./scripts/test.sh`
+
+ You should see the following or similar output:
+
+ Chrome: Runner reset.
+ .
+ Total 1 tests (Passed: 1; Fails: 0; Errors: 0) (2.00 ms)
+ Chrome 11.0.696.57 Mac OS: Run 1 tests (Passed: 1; Fails: 0; Errors 0) (2.00 ms)
+
+ Yay! The test passed!
+
+# Experiments
+
+* Add another binding to `index.html`. For example:
+
+ <p>Total number of phones: {{phones.length}}</p>
+
+* Create a new model property in the controller and bind to it from the template. For example:
+
+ this.hello = "Hello, World!"
+
+* Create a repeater that constructs a simple table:
+
+ <table>
+ <tr><th>row number</th></tr>
+ <tr ng:repeat="i in [0, 1, 2, 3, 4, 5, 6, 7]"><td>{{i}}</td></tr>
+ </table>
+
+ Now, make the list 1-based by incrementing `i` by one in the binding:
- 2. Open a new browser tab or window, navigate to http://localhost:9876, and choose "strict
- mode". At this point, you can leave this tab open and forget about it. JsTestDriver will
- use it to execute our tests and report the results in the terminal.
+ <table>
+ <tr><th>row number</th></tr>
+ <tr ng:repeat="i in [0, 1, 2, 3, 4, 5, 6, 7]"><td>{{i+1}}</td></tr>
+ </table>
- 3. Execute the test by running `./scripts/test.sh`
+* Make the unit test fail by changing the `toBe(3)` statement to `toBe(4)`, and rerun the
+`./scripts/test.sh` script.
-You should see the following or similar output:
- Chrome: Runner reset.
- .
- Total 1 tests (Passed: 1; Fails: 0; Errors: 0) (2.00 ms)
- Chrome 11.0.696.57 Mac OS: Run 1 tests (Passed: 1; Fails: 0; Errors 0) (2.00 ms)
+# Summary
-Yay! The test passed! Now, let's go to Step 3 to learn how to add full text search to the app.
+You now have a dynamic app that features separate model, view, and controller components, and
+you're testing as you go. Now, let's go to step 3 to learn how to add full text search to the app.
<table id="tutorial_nav">
diff --git a/docs/content/tutorial/step_03.ngdoc b/docs/content/tutorial/step_03.ngdoc
index 812f58bb..53eaebc8 100755
--- a/docs/content/tutorial/step_03.ngdoc
+++ b/docs/content/tutorial/step_03.ngdoc
@@ -20,15 +20,15 @@ eye on it, and quickly detects regressions.
1. Reset your workspace to Step 3 using:
- git checkout --force step-3
+ git checkout --force step-3
- or
+ or
- ./goto_step.sh 3
+ ./goto_step.sh 3
2. Refresh your browser or check the app out on {@link
-http://angular.github.com/angular-phonecat/step-3/app our server}. The app now has a search box.
-The phone list on the page changes depending on what a user types into the search box.
+http://angular.github.com/angular-phonecat/step-3/app angular's server}. The app now has a search
+box. The phone list on the page changes depending on what a user types into the search box.
The most important changes are listed below. You can see the full diff on {@link
https://github.com/angular/angular-phonecat/compare/step-2...step-3
@@ -71,15 +71,15 @@ sync.
When changes to the data model cause the repeater's input to change, the repeater efficiently
updates the DOM to reflect the current state of the model.
-* Use of `$filter`. The `{@link angular.Array.filter $filter}` method, uses the `query` value, to
+* Use of `$filter`. The {@link angular.Array.filter $filter} method, uses the `query` value, to
create a new array that contains only those records that match the `query`.
-* `ng:repeat` automatically updates the view in response to the changing number of phones returned
-by the `$filter`. The process is completely transparent to the developer.
+ `ng:repeat` automatically updates the view in response to the changing number of phones returned
+ by the `$filter`. The process is completely transparent to the developer.
## Test
-In Step 2, we learned how to write and run unit tests. Unit tests are perfect for testing
+In step 2, we learned how to write and run unit tests. Unit tests are perfect for testing
controllers and other components of our application written in JavaScript, but they can't easily
test DOM manipulation or the wiring of our application. For these, an end-to-end test is a much
better choice.
@@ -117,17 +117,48 @@ angular's end-to-end test runner}.
To run the end-to-end test, open the following in a new browser tab:
-* node.js users: http://localhost:8000/test/e2e/runner.html
+* node.js users: {@link http://localhost:8000/test/e2e/runner.html}
* users with other http servers:
-http://localhost:[*port-number*]/[*context-path*]/test/e2e/runner.html
-* casual reader: http://angular.github.com/angular-phonecat/step-3/test/e2e/runner.html
+`http://localhost:[*port-number*]/[*context-path*]/test/e2e/runner.html`
+* casual reader: {@link http://angular.github.com/angular-phonecat/step-3/test/e2e/runner.html}
This test verifies that the search box and the repeater are correctly wired together. Notice how
easy it is to write end-to-end tests in angular. Although this example is for a simple test, it
really is that easy to set up any functional, readable, end-to-end test.
-Now that you've verified everything, go to Step 4 to learn how to add sorting capability to the
-phone list app.
+# Experiments
+
+* Display the current value of the `query` model by adding a `{{query}}` binding into the
+`index.html` template, and see how it changes when you type in the input box.
+
+* Change `index.html` to reflect the current search query in the html title by replacing the title
+tag in the head section with:
+
+ <title>Google Phone Gallery: {{query}}</title>`
+
+ If you reload the page, you won't see the expected result. This is because the "query" model
+ lives in the scope defined by:
+
+ <body ng:controller="PhoneListCtrl">
+
+ In order to be able to bind to the query mode from `<title>`, we need to move the
+ `ng:controller` declaration to an element that is a common parent for both the body and title
+ elements. In our case that's the html element:
+
+ <html ng:controller="PhoneListCtrl">
+
+* Make the end-to-end test fail by changing the first `toBe(3)` statement to `toBe(4)`, and
+refresh the end-to-end test runner tab in the browser to rerun the test.
+* Add a `wait();` statement into the end-to-end test and rerun it. You'll see the runner pausing,
+giving you the opportunity to explore the state of your application displayed in the browser. The
+app is live! Change the search query to prove it. This is great for troubleshooting end-to-end
+tests.
+
+
+# Summary
+
+With full text search under our belt and a test to verify it, let's go to step 4 to learn how to
+add sorting capability to the phone app.
<table id="tutorial_nav">
<tr>
diff --git a/docs/content/tutorial/step_04.ngdoc b/docs/content/tutorial/step_04.ngdoc
index c1fd00bb..2ca34929 100755
--- a/docs/content/tutorial/step_04.ngdoc
+++ b/docs/content/tutorial/step_04.ngdoc
@@ -12,23 +12,23 @@ Diff}</td>
</tr>
</table>
-In this step, you will add a feature to let your users select the order of the items in the phone
+In this step, you will add a feature to let your users control the order of the items in the phone
list. The dynamic ordering is implemented by creating a new model property, wiring it together
with the repeater, and letting the data binding magic do the rest of the work.
1. Reset your workspace to Step 4 using:
- git checkout --force step-4
+ git checkout --force step-4
-or
+ or
- ./goto_step.sh 4
+ ./goto_step.sh 4
2. Refresh your browser or check the app out on {@link
-http://angular.github.com/angular-phonecat/step-4/app our server}. You should see that in addition
-to the search box, the app displays a drop down menu that allows users to control the order in
-which the phones are listed.
+http://angular.github.com/angular-phonecat/step-4/app angular's server}. You should see that in
+addition to the search box, the app displays a drop down menu that allows users to control the
+order in which the phones are listed.
The most important changes are listed below. You can see the full diff on {@link
https://github.com/angular/angular-phonecat/compare/step-3...step-4
@@ -67,13 +67,14 @@ In the `index.html` template we made the following changes:
* First, we added a `<select>` html element named `orderProp`, so that our users can pick from the
two provided sorting options.
-* We then chained the `$filter` method with `{@link angular.Array.orderBy $orderBy}` method to
-further process the input into the repeater.
+* We then chained the `$filter` method with {@link angular.Array.orderBy `$orderBy`} method to
+further process the input into the repeater. `$orderBy` is a utility method similar to {@link
+angular.Array.filter `$filter`}, but instead of filtering an array, it reorders it.
Angular creates a two way data-binding between the select element and the `orderProp` model.
`orderProp` is then used as the input for the `$orderBy` method.
-As we discussed in the section about data-binding and the repeater in Step 3, whenever the model
+As we discussed in the section about data-binding and the repeater in step 3, whenever the model
changes (for example because a user changes the order with the select drop down menu), angular's
data-binding will cause the view to automatically update. No bloated DOM manipulation code is
necessary!
@@ -108,6 +109,12 @@ record. This property is used to order phones by age.
not set the default value here, angular would have used the value of the first `<option>` element
(`'name'`) when it initialized the data model.
+ This is a good time to talk about two-way data-binding. Notice that when the app is loaded in
+ the browser, "Newest" is selected in the drop down menu. This is because we set `orderProp` to
+ `'age'` in the controller. So the binding works in the direction from our model to the UI. Now
+ if you select "Alphabetically" in the drop down menu, the model will be updated as well and the
+ phones will be reordered. That is the data-binding doing its job in the opposite direction —
+ from the UI to the model.
@@ -118,7 +125,6 @@ the unit test first.
__`test/unit/controllerSpec.js`:__
<pre>
-/* jasmine specs for controllers go here */
describe('PhoneCat controllers', function() {
describe('PhoneListCtrl', function(){
@@ -150,10 +156,10 @@ shared by all tests in the nearest `describe` block.
To run the unit tests, once again execute the `./scripts/test.sh` script and you should see the
following output.
- Chrome: Runner reset.
- ..
- Total 2 tests (Passed: 2; Fails: 0; Errors: 0) (3.00 ms)
- Chrome 11.0.696.57 Mac OS: Run 2 tests (Passed: 2; Fails: 0; Errors 0) (3.00 ms)
+ Chrome: Runner reset.
+ ..
+ Total 2 tests (Passed: 2; Fails: 0; Errors: 0) (3.00 ms)
+ Chrome 11.0.696.57 Mac OS: Run 2 tests (Passed: 2; Fails: 0; Errors 0) (3.00 ms)
Let's turn our attention to the end-to-end test.
@@ -185,7 +191,18 @@ can see them running on {@link
http://angular.github.com/angular-phonecat/step-4/test/e2e/runner.html
angular's server}.
-Now that you have added list sorting and tested the app, go to Step 5 to learn about angular
+# Experiments
+
+* In the `PhoneListCtrl` controller, remove the statement that sets the `orderProp` value and
+you'll see that the ordering as well as the current selection in the dropdown menu will default to
+"Alphabetical".
+
+* Add an `{{orderProp}}` binding into the `index.html` template to display its current value as
+text.
+
+# Summary
+
+Now that you have added list sorting and tested the app, go to step 5 to learn about angular
services and how angular uses dependency injection.
diff --git a/docs/content/tutorial/step_05.ngdoc b/docs/content/tutorial/step_05.ngdoc
index 0c8f0dde..3727d8f0 100755
--- a/docs/content/tutorial/step_05.ngdoc
+++ b/docs/content/tutorial/step_05.ngdoc
@@ -20,15 +20,16 @@ the `PhoneListCtrl` controller.
1. Reset your workspace to Step 5 using:
- git checkout --force step-5
+ git checkout --force step-5
-or
+ or
+
+ ./goto_step.sh 5
- ./goto_step.sh 5
2. Refresh your browser or check the app out on {@link
-http://angular.github.com/angular-phonecat/step-5/app our server}. You should now see a list of 20
-phones.
+http://angular.github.com/angular-phonecat/step-5/app angular's server}. You should now see a list
+of 20 phones.
The most important changes are listed below. You can see the full diff on {@link
@@ -166,46 +167,58 @@ in the production code behind the scenes.
To create the controller in the test environment, do the following:
- * Create a root scope object by calling `angular.scope()`
+* Create a root scope object by calling `angular.scope()`
- * Call `scope.$new(PhoneListCtrl)` to get angular to create the child scope associated with
- the `PhoneListCtrl` controller.
+* Call `scope.$new(PhoneListCtrl)` to get angular to create the child scope associated with the
+`PhoneListCtrl` controller.
Because our code now uses the `$xhr` service to fetch the phone list data in our controller,
before we create the `PhoneListCtrl` child scope, we need to tell the testing harness to expect an
incoming request from the controller. To do this we:
- * Use the `{@link angular.scope.$service $service}` method to retrieve the `$browser` service,
- a service that angular uses to represent 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.
+* Use the {@link angular.scope.$service `$service`} method to retrieve the `$browser` service, a
+service that angular uses to represent 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 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 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.
+* 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.
+* Finally, we make the assertions, verifying that the phone model now exists on the scope.
To run the unit tests, execute the `./scripts/test.sh` script and you should see the following
output.
- Chrome: Runner reset.
- ..
- Total 2 tests (Passed: 2; Fails: 0; Errors: 0) (3.00 ms)
- Chrome 11.0.696.57 Mac OS: Run 2 tests (Passed: 2; Fails: 0; Errors 0) (3.00 ms)
+ Chrome: Runner reset.
+ ..
+ Total 2 tests (Passed: 2; Fails: 0; Errors: 0) (3.00 ms)
+ Chrome 11.0.696.57 Mac OS: Run 2 tests (Passed: 2; Fails: 0; Errors 0) (3.00 ms)
+
+
+# Experiments
+
+* At the bottom of `index.html`, add a `{{phones}}` binding to see the list of phones displayed in
+json format.
+* In the `PhoneListCtrl` controller, pre-process the xhr response by limiting the number of phones
+to the first 5 in the list. Use the following code in the xhr callback:
+
+ self.phones = response.splice(0, 5);
+
+
+# Summary
Now that you have learned how easy it is to use angular services (thanks to angular's
-implementation of dependency injection), go to Step 6, where you will add some thumbnail images of
+implementation of dependency injection), go to step 6, where you will add some thumbnail images of
phones and some links.
-
<table id="tutorial_nav">
<tr>
<td id="previous_step">{@link tutorial.step_04 Previous}</td>
diff --git a/docs/content/tutorial/step_06.ngdoc b/docs/content/tutorial/step_06.ngdoc
index 91862b73..19d0edbc 100755
--- a/docs/content/tutorial/step_06.ngdoc
+++ b/docs/content/tutorial/step_06.ngdoc
@@ -19,15 +19,15 @@ about the phones in the catalog.
1. Reset your workspace to Step 6 using:
- git checkout --force step-6
+ git checkout --force step-6
-or
+ or
- ./goto_step.sh 6
+ ./goto_step.sh 6
2. Refresh your browser or check the app out on {@link
-http://angular.github.com/angular-phonecat/step-6/app our server}. You should now see links and
-images of the phones in the list.
+http://angular.github.com/angular-phonecat/step-6/app angular's server}. You should now see links
+and images of the phones in the list.
The most important changes are listed below. You can see the full diff on {@link
https://github.com/angular/angular-phonecat/compare/step-5...step-6
@@ -102,7 +102,17 @@ can see them running on {@link
http://angular.github.com/angular-phonecat/step-6/test/e2e/runner.html
angular's server}.
-Now that you have added phone images and links, go to Step 7 to learn about angular layout
+# Experiments
+
+* Replace the `ng:src` directive with a plain old `<src>` attribute, and using tools such as
+Firebug, or Chrome's Web Inspector, or by inspecting the webserver access logs, confirm that the
+app is indeed making an extraneous request to `/app/%7B%7Bphone.imageUrl%7D%7D` (or
+`/app/index.html/{{phone.imageUrl}}`).
+
+
+# Summary
+
+Now that you have added phone images and links, go to step 7 to learn about angular layout
templates and how angular makes it easy to create applications that have multiple views.
diff --git a/docs/content/tutorial/step_07.ngdoc b/docs/content/tutorial/step_07.ngdoc
index 3b8b9b45..65f9f4c4 100755
--- a/docs/content/tutorial/step_07.ngdoc
+++ b/docs/content/tutorial/step_07.ngdoc
@@ -18,16 +18,16 @@ multiple views by adding routing.
1. Reset your workspace to Step 7 using:
- git checkout --force step-7
+ git checkout --force step-7
-or
+ or
- ./goto_step.sh 7
+ ./goto_step.sh 7
-2. Refresh your browser, but be sure that there is nothing in the url after app/index.html, or
-check the app out on {@link http://angular.github.com/angular-phonecat/step-7/app our server}.
-Note that you are redirected to `app/index.html#/phones` and the same phone list appears in the
-browser. When you click on a phone link the stub of a phone detail page is displayed.
+2. Refresh your browser, but be sure that there is nothing in the url after `app/index.html`, or
+check the app out on {@link http://angular.github.com/angular-phonecat/step-7/app angular's
+server}. Note that you are redirected to `app/index.html#/phones` and the same phone list appears
+in the browser. When you click on a phone link the stub of a phone detail page is displayed.
The most important changes are listed below. You can see the full diff on {@link
@@ -36,7 +36,7 @@ GitHub}:
## What's going on here?
-Our app is slowly growing and becoming more complex. Before Step 7, the app provided our users
+Our app is slowly growing and becoming more complex. Before step 7, the app provided our users
with a single view (the list of all phones), and all of the template code was located in the
`index.html` file. The next step in building the app is the addition of a view that will show
detailed information about each of the devices in our list.
@@ -84,14 +84,15 @@ service and used this service to declare that our application consists of two di
* The phone list view will be shown when the URL hash fragment is `/phone`. To construct this
view, angular will use the `phone-list.html` template and the `PhoneListCtrl` controller.
-* The phone details view will be show when the URL hash fragment matches '/phone/[phoneId]'. To
+* The phone details view will be shown when the URL hash fragment matches '/phone/[phoneId]'. To
construct this view, angular will use the `phone-detail.html` template and the `PhoneDetailCtrl`
controller.
We reused the `PhoneListCtrl` controller for the first view and we added an empty
`PhoneDetailCtrl` controller to the `app/js/controllers.js` file for the second one.
-The statement `$route.otherwise({redirectTo: '/phones'});`, triggers a redirection to `/phones`
-when none of our routes is matched.
+
+The statement `$route.otherwise({redirectTo: '/phones'})` triggers a redirection to `/phones` when
+the browser address doesn't match either of our routes.
Thanks to the `$route.parent(this);` statement and `ng:controller="PhoneCatCtrl"` declaration in
the `index.html` template, the `PhoneCatCtrl` controller has a special role in our app. It is the
@@ -99,13 +100,17 @@ the `index.html` template, the `PhoneCatCtrl` controller has a special role in o
`PhoneDetailCtrl`). The sub-controllers inherit the model properties and behavior from the root
controller.
-
Note the use of the `:phoneId` parameter in the second route declaration (`'/phones/:phoneId'`).
-When the current URL matches this route, the `$route` service extracts the phoneId string from the
-current URL and provides it to our controller via the `$route.current.params` map. We will use the
-`phoneId` parameter in the `phone-details.html` template.
-
+When the current URL matches this route, the `$route` service extracts the `phoneId` string from
+the current URL and provides it to our controller via the `$route.current.params` map. We will use
+the `phoneId` parameter in the `phone-details.html` template thanks to the alias created in the
+{@link angular.service.$route `$route.onChange`} callback.
+In this `onChange` callback, we aliased url parameters extracted from the current route to the
+`params` property in the root scope. This model property is inherited by child scopes created for
+our routes and accessible by their controllers and templates, just like the `phone-list.html`
+template demonstrates.
+
## Template
@@ -161,10 +166,12 @@ __`app/partials/phone-list.html`:__
TBD: detail view for {{params.phoneId}}
</pre>
+Note how we are using `params` model defined in the `PhoneCanCtrl` controller.
+
## Test
-To automatically verify that everything is wired properly, we wrote end to end tests that navigate
+To automatically verify that everything is wired properly, we wrote end-to-end tests that navigate
to various URLs and verify that the correct view was rendered.
<pre>
@@ -195,7 +202,22 @@ http://angular.github.com/angular-phonecat/step-7/test/e2e/runner.html
angular's server}.
-With the routing set up and the phone list view implemented, we're ready to go to Step 8 to
+# Experiments
+
+* Try to add an `{{orderProp}}` binding to `index.html`, and you'll see that nothing happens even
+when you are in the phone list view. This is because the `orderProp` model is visible only in the
+scope managed by `PhoneListCtrl`, which is associated with the `<ng:view>` element. If you add the
+same binding into the `phone-list.html` template, the binding will work as expected.
+
+* In `PhoneCatCtrl`, create a new model called "`firstName`" with `this.hero = 'Zoro'`. In
+`PhoneListCtrl` let's shadow it with `this.hero = 'Batman'`, and in `PhoneDetailCtrl` we'll use
+`this.hero = "Captain Proton"`. Then add the `<p>hero = {{hero}}</p>` to all three of our
+templates (`index.html`, `phone-list.html`, and `phone-detail.html`). Open the app and you'll see
+scope inheritance and model property shadowing do some wonders.
+
+# Summary
+
+With the routing set up and the phone list view implemented, we're ready to go to step 8 to
implement the phone details view.
<table id="tutorial_nav">
diff --git a/docs/content/tutorial/step_08.ngdoc b/docs/content/tutorial/step_08.ngdoc
index 2d5c0ab9..ec542f0d 100755
--- a/docs/content/tutorial/step_08.ngdoc
+++ b/docs/content/tutorial/step_08.ngdoc
@@ -18,16 +18,15 @@ a phone in the phone list.
1. Reset your workspace to Step 8 using:
- git checkout --force step-8
+ git checkout --force step-8
-or
+ or
- ./goto_step.sh 8
+ ./goto_step.sh 8
2. Refresh your browser or check the app out on {@link
-http://angular.github.com/angular-phonecat/step-8/app our server}. Now when you click on a phone
-on the list, the phone details page with phone-specific information is displayed.
-
+http://angular.github.com/angular-phonecat/step-8/app angular's server}. Now when you click on a
+phone on the list, the phone details page with phone-specific information is displayed.
To implement the phone details view we will use {@link angular.services.$xhr $xhr} to fetch our
data, and we'll flesh out the `phone-details.html` view template.
@@ -87,14 +86,15 @@ function PhoneDetailCtrl($xhr) {
//PhoneDetailCtrl.$inject = ['$xhr'];
</pre>
-
+To construct the URL for the HTTP request, we use `params.phoneId` extracted from the current
+route in the `PhoneCatCtrl` controller.
## Template
The TBD placeholder line has been replaced with lists and bindings that comprise the phone
-details. Note where we use the angular `{{ expression }}` markup and `ng:repeater`s to project
-phone data from our model into the view.
+details. Note where we use the angular `{{expression}}` markup and `ng:repeater`s to project phone
+data from our model into the view.
__`app/partials/phone-details.html`:__
@@ -131,7 +131,7 @@ __`app/partials/phone-details.html`:__
## Test
We wrote a new unit test that is similar to the one we wrote for the `PhoneListCtrl` controller in
-Step 5.
+step 5.
__`test/unit/controllerSpec.js`:__
<pre>
@@ -152,10 +152,10 @@ __`test/unit/controllerSpec.js`:__
To run the unit tests, execute the `./scripts/test.sh` script and you should see the following
output.
- Chrome: Runner reset.
- ...
- Total 3 tests (Passed: 3; Fails: 0; Errors: 0) (5.00 ms)
- Chrome 11.0.696.57 Mac OS: Run 3 tests (Passed: 3; Fails: 0; Errors 0) (5.00 ms)
+ Chrome: Runner reset.
+ ...
+ Total 3 tests (Passed: 3; Fails: 0; Errors: 0) (5.00 ms)
+ Chrome 11.0.696.57 Mac OS: Run 3 tests (Passed: 3; Fails: 0; Errors 0) (5.00 ms)
We also added a new end-to-end test that navigates to the Nexus S detail page and verifies that
@@ -184,8 +184,19 @@ can see them running on {@link
http://angular.github.com/angular-phonecat/step-8/test/e2e/runner.html
angular's server}.
-Now the phone details view is in place, proceed to Step 9 to learn how to write your own custom
-display filter.
+# Experiments
+
+* Stretching:
+ * Alternate chin-to-chest with look-at-ceiling. Repeat eight times.
+ * Now do ear-to-shoulder (left ear to left shoulder, right to right. Caution: do not try left
+ ear to right shoulder!). Repeat eight times.
+ * Finally, do chin-to-shoulder, left right left right. Repeat eight times.
+
+
+# Summary
+
+Now that the phone details view is in place, proceed to step 9 to learn how to write your own
+custom display filter.
<table id="tutorial_nav">
<tr>
diff --git a/docs/content/tutorial/step_09.ngdoc b/docs/content/tutorial/step_09.ngdoc
index 1009217d..a5e0a15c 100755
--- a/docs/content/tutorial/step_09.ngdoc
+++ b/docs/content/tutorial/step_09.ngdoc
@@ -17,15 +17,15 @@ In this step you will learn how to create your own custom display filter.
1. Reset your workspace to Step 9 using:
- git checkout --force step-9
+ git checkout --force step-9
-or
+ or
- ./goto_step.sh 9
+ ./goto_step.sh 9
2. Refresh your browser or check the app out on {@link
-http://angular.github.com/angular-phonecat/step-9/app our server}. Navigate to one of the detail
-pages.
+http://angular.github.com/angular-phonecat/step-9/app angular's server}. Navigate to one of the
+detail pages.
In the previous step, the details page displayed either "true" or "false" to indicate whether
certain phone features were present or not. We have used a custom filter to convert those text
@@ -38,8 +38,8 @@ GitHub}:
## Custom Filter
-In order to create a new filter, simply register your custom filter function with the `{@link
-angular.filter angular.filter}` API.
+In order to create a new filter, simply register your custom filter function with the {@link
+angular.filter `angular.filter`} API.
__`app/js/filters.js`:__
<pre>
@@ -48,7 +48,7 @@ angular.filter('checkmark', function(input) {
});
</pre>
-The name of our filter is "checkmark". The `input` evaluates to either "true" or "false", and we
+The name of our filter is "checkmark". The `input` evaluates to either `true` or `false`, and we
return one of two unicode characters we have chosen to represent true or false (`\u2713` and
`\u2718`).
@@ -105,13 +105,30 @@ describe('checkmark filter', function() {
To run the unit tests, execute the `./scripts/test.sh` script and you should see the following
output.
- Chrome: Runner reset.
- ....
- Total 4 tests (Passed: 4; Fails: 0; Errors: 0) (3.00 ms)
- Chrome 11.0.696.57 Mac OS: Run 4 tests (Passed: 4; Fails: 0; Errors 0) (3.00 ms)
+ Chrome: Runner reset.
+ ....
+ Total 4 tests (Passed: 4; Fails: 0; Errors: 0) (3.00 ms)
+ Chrome 11.0.696.57 Mac OS: Run 4 tests (Passed: 4; Fails: 0; Errors 0) (3.00 ms)
-Now that you have learned how to write and test a custom filter, go to Step 10 to learn how we can
+# Experiments
+
+* Let's experiment with some of the {@link angular.filter built-in angular filters} and add the
+following bindings to `index.html`:
+ * `{{ "lower cap string" | uppercase }}`
+ * `{{ {foo: "bar", baz: 23} | json }}`
+ * `{{ 1304375948024 | date }}`
+ * `{{ 1304375948024 | date:"'MM/dd/yyyy @ h:mma" }}`
+
+* We can also create a model with an input element, and combine it with a filtered binding. Add
+the following to index.html:
+
+ <input name="userInput"> Uppercased: {{ userInput | uppercase }}
+
+
+# Summary
+
+Now that you have learned how to write and test a custom filter, go to step 10 to learn how we can
use angular to enhance the phone details page further.
<table id="tutorial_nav">
diff --git a/docs/content/tutorial/step_10.ngdoc b/docs/content/tutorial/step_10.ngdoc
index 1614c414..52554a71 100644
--- a/docs/content/tutorial/step_10.ngdoc
+++ b/docs/content/tutorial/step_10.ngdoc
@@ -17,18 +17,18 @@ In this step, you will add a clickable phone image swapper to the phone details
1. Reset your workspace to Step 10 using:
- git checkout --force step-10
+ git checkout --force step-10
-or
+ or
- ./goto_step.sh 10
+ ./goto_step.sh 10
2. Refresh your browser or check the app out on {@link
-http://angular.github.com/angular-phonecat/step-10/app our server}.
+http://angular.github.com/angular-phonecat/step-10/app angular's server}.
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.
+clicking on the desired thumbnail image. Let's have a look at how we can do this with angular.
The most important changes are listed below. You can see the full diff on {@link
https://github.com/angular/angular-phonecat/compare/step-9...step-10
@@ -56,8 +56,8 @@ function PhoneDetailCtrl($xhr) {
//PhoneDetailCtrl.$inject = ['$xhr'];
</pre>
-In the `PhoneDetailCtrl` controller, the statement `self.mainImageUrl = response.images[0];`
-creates the `mainImageUrl` model property and set its default value to the first phone image url.
+In the `PhoneDetailCtrl` controller, we created the `mainImageUrl` model property and set its
+default value to the first phone image url.
We also created a `setImage` controller method to change the value of `mainImageUrl`.
@@ -80,7 +80,7 @@ __`app/partials/phone-detail.html`:__
We bound the `ng:src` attribute of the large image to the `mainImageUrl` property.
-We also registered an `{@link angular.directive.ng:click ng:click}` handler with thumbnail images.
+We also registered an {@link angular.directive.ng:click `ng:click`} handler with thumbnail images.
When a user clicks on one of the thumbnail images, the handler will use the `setImage` controller
method to change the value of the `mainImageUrl` property to the url of the thumbnail image.
@@ -122,8 +122,31 @@ can see them running on {@link
http://angular.github.com/angular-phonecat/step-8/test/e2e/runner.html
angular's server}.
+# Experiments
-With the phone image swapper in place, we're ready for Step 11 (the last step!) to learn an even
+* Let's add a new controller method to `PhoneCatCtrl`:
+
+ this.hello(name) = function(name) {
+ alert('Hello ' + (name || 'world') + '!');
+ }
+
+ and add:
+
+ <button ng:click="hello('Elmo')">Hello</button>
+
+ to the `index.html` template.
+
+ The controller methods are inherited between controllers/scopes, so you can use the same snippet
+ in the `phone-list.html` template as well.
+
+* Move the `hello` method from `PhoneCatCtrl` to `PhoneListCtrl` and you'll see that the button
+declared in `index.html` will stop working, while the one declared in the `phone-list.html`
+template remains operational.
+
+
+# Summary
+
+With the phone image swapper in place, we're ready for step 11 (the last step!) to learn an even
better way to fetch data.
<table id="tutorial_nav">
diff --git a/docs/content/tutorial/step_11.ngdoc b/docs/content/tutorial/step_11.ngdoc
index 5dc45d90..c6802c17 100644
--- a/docs/content/tutorial/step_11.ngdoc
+++ b/docs/content/tutorial/step_11.ngdoc
@@ -17,14 +17,14 @@ In this step, you will improve the way our app fetches data.
1. Reset your workspace to Step 11 using:
- git checkout --force step-11
+ git checkout --force step-11
-or
+ or
- ./goto_step.sh 11
+ ./goto_step.sh 11
2. Refresh your browser or check the app out on {@link
-http://angular.github.com/angular-phonecat/step-11/app our server}.
+http://angular.github.com/angular-phonecat/step-11/app angular's server}.
The last improvement we will make to our app is to define a custom service that represents a
@@ -65,7 +65,7 @@ service - 'Phone' - and a factory function. The factory function is similar to a
constructor in that both can declare dependencies via function arguments. The Phone service
declared a dependency on the `$resource` service.
-The `{@link angular.service.$resource $resource}` service makes it easy to create a {@link
+The {@link angular.service.$resource `$resource`} service makes it easy to create a {@link
http://en.wikipedia.org/wiki/Representational_State_Transfer RESTful} client with just a few lines
of code. This client can then be used in our application, instead of the lower-level `$xhr`
service.
@@ -125,8 +125,6 @@ Sometimes, relying on the future object and data-binding alone is not sufficient
we require, so in these cases, we can add a callback to process the server response. The
`PhoneDetailCtrl` controller illustrates this by setting the `mainImageUrl` in a callback.
-
-
## Test
@@ -210,30 +208,16 @@ describe('PhoneCat controllers', function() {
To run the unit tests, execute the `./scripts/test.sh` script and you should see the following
output.
- Chrome: Runner reset.
- ....
- Total 4 tests (Passed: 4; Fails: 0; Errors: 0) (3.00 ms)
- Chrome 11.0.696.57 Mac OS: Run 4 tests (Passed: 4; Fails: 0; Errors 0) (3.00 ms)
-
-
-There you have it! We have created a web app in a relatively short amount of time.
+ Chrome: Runner reset.
+ ....
+ Total 4 tests (Passed: 4; Fails: 0; Errors: 0) (3.00 ms)
+ Chrome 11.0.696.57 Mac OS: Run 4 tests (Passed: 4; Fails: 0; Errors 0) (3.00 ms)
-## Closing Notes:
-* For more details and examples of the angular concepts we touched on in this tutorial, see the
-{@link guide Developer Guide}.
+# Summary
-* For several more examples of code, see the {@link cookbook Cookbook}.
-
-* When you are ready to start developing a project using angular, we recommend that you bootstrap
-your development with the {@link https://github.com/angular/angular-seed angular seed} project.
-
-* We hope this tutorial was useful to you and that you learned enough about angular to make you
-want to learn more. We especially hope you are inspired to go out and develop angular web apps of
-your own, and that you might be interested in {@link contribute contributing} to angular.
+There you have it! We have created a web app in a relatively short amount of time.
-* If you have questions or feedback or just want to say "hi", please post a message at
-https://groups.google.com/forum/#!forum/angular.
<table id="tutorial_nav">
<tr>