mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-03-16 23:30:23 +00:00
Latest greatest tutorial udpates.
This commit is contained in:
parent
525e444a0f
commit
9d9117384f
13 changed files with 379 additions and 202 deletions
|
|
@ -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}.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
Now let's go to Step 1 and add some content to the web app.
|
||||
# Summary
|
||||
|
||||
Now let's go to step 1 and add some content to the web app.
|
||||
|
||||
<table id="tutorial_nav">
|
||||
<tr>
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
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`
|
||||
3. Execute the test by running `./scripts/test.sh`
|
||||
|
||||
You should see the following or similar output:
|
||||
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)
|
||||
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! Now, let's go to Step 3 to learn how to add full text search to the app.
|
||||
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:
|
||||
|
||||
<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>
|
||||
|
||||
* Make the unit test fail by changing the `toBe(3)` statement to `toBe(4)`, and rerun the
|
||||
`./scripts/test.sh` script.
|
||||
|
||||
|
||||
# Summary
|
||||
|
||||
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">
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
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)
|
||||
|
||||
|
||||
# Summary
|
||||
|
||||
There you have it! We have created a web app in a relatively short amount of time.
|
||||
|
||||
## Closing Notes:
|
||||
|
||||
* For more details and examples of the angular concepts we touched on in this tutorial, see the
|
||||
{@link guide Developer Guide}.
|
||||
|
||||
* For several more examples of code, see the {@link cookbook Cookbook}.
|
||||
|
||||
* When you are ready to start developing a project using angular, we recommend that you bootstrap
|
||||
your development with the {@link https://github.com/angular/angular-seed angular seed} project.
|
||||
|
||||
* We hope this tutorial was useful to you and that you learned enough about angular to make you
|
||||
want to learn more. We especially hope you are inspired to go out and develop angular web apps of
|
||||
your own, and that you might be interested in {@link contribute contributing} to angular.
|
||||
|
||||
* If you have questions or feedback or just want to say "hi", please post a message at
|
||||
https://groups.google.com/forum/#!forum/angular.
|
||||
|
||||
<table id="tutorial_nav">
|
||||
<tr>
|
||||
|
|
|
|||
Loading…
Reference in a new issue