Tutorial files for your perusal.

This commit is contained in:
Kenneth R. Culp 2011-04-26 09:54:08 -07:00 committed by Igor Minar
parent 4738d49e1c
commit 0a604bdb90
13 changed files with 1475 additions and 0 deletions

87
docs/tutorial.ngdoc Executable file
View file

@ -0,0 +1,87 @@
@workInProgress
@ngdoc overview
@name Tutorial
@description
<table id="tutorial_nav">
<tr>
<td id="previous_step">Previous</td>
<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-0/app Example}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
<td id="code_diff">Code Diff</td>
<td id="next_step">{@link tutorial.step_1 Next}</td>
</tr>
</table>
Welcome to the angular tutorial! Before you begin, you can check out the finished app here:
{@link http://angular.github.com/angular-phonecat/step-11/app/ The Completed Tutorial App}. Also,
if you missed the {@link tutorial_intro Intro to Tutorial} doc, it provides some background info,
and describes different options you have in working through the tutorial.
We'll begin the tutorial by creating a basic page, and then we'll add functionality to our app on
each subsequent step.
# Step 0
The following sample code is our starting point. It is a static HTML page that displays next to
nothing, but it has everything we need to proceed. You can think of this bit of code as our
prototype template, consisting of basic HTML tags and some key angular {@link angular.directive
directives}.
__`app/index.html`:__
<pre>
<!doctype html>
<html xmlns:ng="http://angularjs.org/">
<head>
<meta charset="utf-8">
<title>my angular app</title>
<link rel="stylesheet" href="css/app.css"/>
</head>
<body>
Nothing here yet!
<script src="lib/angular/angular.js" ng:autobind></script>
</body>
</html>
</pre>
## Discussion:
Although our app doesn't appear to do anything dynamic, note the following:
* __... `xmlns:ng="http://angularjs.org"` ...__ This `xmlns` declaration for the `ng` namespace
must be specified if you use XHTML, or if you are targeting IE older than 9 (regardless of whether
you are using XHTML or HTML).
* __`<script src="lib/angular/angular.js"` ...__ This downloads the `angular.js` bootstrap script
and registers a callback that will be executed by the browser when the HTML is fully downloaded.
When the callback is executed, angular looks for the {@link angular.directive.ng:autobind
ng:autobind} attribute. If `ng:autobind` is found, it signals angular to compile and manage the
whole page.
Note: If you elected not to download any tutorial files but still want to try out some angular
code on your system, you can change the relative path to the `angular.js` script in your
template from `./lib/angular/angular.js` to the following:
<script src="http://code.angularjs.org/angular-0.9.14.js" ng:autobind></script>
This will bootstrap angular from the angular server instead of from a local file.
* To try this code out in your browser, you need to navigate to the step-0 page (you are currently
on Step 0 of the tutorial). If your http server is running, navigate to `app/index.html`.
Remember, this is a relative URL (see the Relative URL section in {@link tutorial_intro Intro to
Tutorial}). The browser will display the same thing as you would see if you go to
http://angular.github.com/angular-phonecat/step-0/app (accessible from Example at the bottom of
the page).
Now we can move on and add some content to our developing web app.
<table id="tutorial_nav">
<tr>
<td id="previous_step">Previous</td>
<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-0/app Example}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
<td id="code_diff">Code Diff</td>
<td id="next_step">{@link tutorial.step_1 Next}</td>
</tr>
</table>

86
docs/tutorial.step_1.ngdoc Executable file
View file

@ -0,0 +1,86 @@
@workInProgress
@ngdoc overview
@name Tutorial: Step 1
@description
<table id="tutorial_nav">
<tr>
<td id="previous_step">{@link tutorial Previous}</td>
<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-1/app Example}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
<td id="code_diff">
{@link https://github.com/angular/angular-phonecat/commit/fa2a351f0ede1666041e407c52e4e5daf448c5f8
Code Diff}</td>
<td id="next_step">{@link tutorial.step_2 Next}</td>
</tr>
</table>
In this step, we will add basic information about two cell phones.
Note: We will usually include only the new code that we added for each step. In this and
subsequent examples, we will leave out code from the previous step that hasn't changed, for
example:
...
<html xmlns:ng="http://angularjs.org">
...
Let's add the following code to `index.html`:
__`app/index.html`:__
<pre>
<head>
...
<title>Google Phone Gallery</title>
...
</head>
...
<ul>
<li>
<span>Nexus S<span>
<p>
Fast just got faster with Nexus S.
</p>
</li>
<li>
<span>Motorola XOOM™ with Wi-Fi<span>
<p>
The Next, Next Generation tablet.
</p>
</li>
</ul>
...
</pre>
## Discussion:
* It's a static web page! We displayed info about two phones! Yay.
* For those of you playing along at home on your own web servers, did you switch to Step 1 and
refresh your browsers?
* __{@link tutorial_intro Using Git:}__
From your `angular-phonecat` directory, run this command:
git checkout step-1
* __{@link tutorial_intro Using Snapshots:}__
From `[install directory]/sandbox`, run this command:
./goto_step.sh 1
When you're ready, let's move on and start using some angular features to turn this static page
into a dynamic web app.
<table id="tutorial_nav">
<tr>
<td id="previous_step">{@link tutorial Previous}</td>
<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-1/app Example}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
<td id="code_diff">
{@link https://github.com/angular/angular-phonecat/commit/fa2a351f0ede1666041e407c52e4e5daf448c5f8
Code Diff}</td>
<td id="next_step">{@link tutorial.step_2 Next}</td>
</tr>
</table>

109
docs/tutorial.step_10.ngdoc Normal file
View file

@ -0,0 +1,109 @@
@workInProgress
@ngdoc overview
@name Tutorial: Step 10
@description
<table id="tutorial_nav">
<tr>
<td id="previous_step">{@link tutorial.step_9 Previous}</td>
<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-10/app Example}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
<td id="code_diff">{@link
https://github.com/angular/angular-phonecat/commit/abe1e13c7d9e725fdd3b811ca5ec28ea0d973aab Code
Diff}</td>
<td id="next_step">{@link tutorial.step_11 Next}</td>
</tr>
</table>
In this step we will add a phone image swapping feature. We want to be able to click on a
thumbnail image in the phone details page, and have that action change the large phone image to
match the selection.
__`app/partials/phone-detail.html`.__
<pre>
<img ng:src="{{mainImageUrl}}" class="phone"/>
<h1>{{phone.name}}</h1>
<p>{{phone.description}}</p>
<ul class="phone-thumbs">
<li ng:repeat="img in phone.images">
<img ng:src="{{img}}" ng:click="setImage(img)">
</li>
</ul>
...
</pre>
__`app/js/controllers.js`.__
<pre>
...
function PhoneDetailCtrl($xhr) {
var self = this;
$xhr('GET', 'phones/' + self.params.phoneId + '.json', function(code, response) {
self.phone = response;
self.mainImageUrl = response.images[0];
});
self.setImage = function(imageUrl) {
self.mainImageUrl = imageUrl;
}
}
//PhoneDetailCtrl.$inject = ['$xhr'];
</pre>
__`test/e2e/scenarios.js`.__
<pre>
/* jasmine-like end2end tests go here */
...
describe('Phone detail view', function() {
beforeEach(function() {
browser().navigateTo('../../app/index.html#/phones/nexus-s');
});
it('should display nexus-s page', function() {
expect(binding('phone.name')).toBe('Nexus S');
});
it('should display "0.large" image as the main phone image', function() {
expect(element('img.phone').attr('src')).toBe('img/phones/nexus-s.0.jpg');
});
it('should swap main image if a thumbnail image is clicked on', function() {
element('.phone-thumbs li:nth-child(3) img').click();
expect(element('img.phone').attr('src')).toBe('img/phones/nexus-s.2.jpg');
element('.phone-thumbs li:nth-child(1) img').click();
expect(element('img.phone').attr('src')).toBe('img/phones/nexus-s.0.jpg');
});
});
});
</pre>
## Discussion:
Adding the phone image swapping feature is fairly straightforward:
- We defined the `mainImageUrl` model variable in the details controller (`PhoneDetailCtrl`) and
set the default value of `mainImageUrl` to the first image in the array of images.
- We created a `setImage` controller method to change `mainImageUrl` to the image clicked on by
the user.
- We registered an `ng:click` handler for thumb images to use the `setImage` controller method.
- And of course, we added e2e tests for our new feature.
<table id="tutorial_nav">
<tr>
<td id="previous_step">{@link tutorial.step_9 Previous}</td>
<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-10/app Example}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
<td id="code_diff">{@link
https://github.com/angular/angular-phonecat/commit/abe1e13c7d9e725fdd3b811ca5ec28ea0d973aab Code
Diff}</td>
<td id="next_step">{@link tutorial.step_11 Next}</td>
</tr>
</table>

113
docs/tutorial.step_11.ngdoc Normal file
View file

@ -0,0 +1,113 @@
@workInProgress
@ngdoc overview
@name Tutorial: Step 11
@description
<table id="tutorial_nav">
<tr>
<td id="previous_step">{@link tutorial.step_10 Previous}</td>
<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-11/app Example}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
<td id="code_diff">{@link
https://github.com/angular/angular-phonecat/commit/46e2bc3ff21a1385d6ef1860c5c242f8e0265379 Code
Diff}</td>
<td id="next_step">Next</td>
</tr>
</table>
And so we arrive at the last step of this tutorial. Here we define a custom service that
represents a {@link http://en.wikipedia.org/wiki/Representational_State_Transfer RESTful} client
object. Using this client object we can make requests for data in an easier way, without having
to deal with the lower-level {@link angular.service.$xhr $xhr} APIs.
__`app/index.html`.__
<pre>
...
<script src="lib/angular/angular.js" ng:autobind></script>
<script src="js/controllers.js"></script>
<script src="js/filters.js"></script>
<script src="js/services.js"></script>
...
</pre>
__`app/js/services.js`.__ (New)
<pre>
angular.service('Phone', function($resource){
return $resource('phones/:phoneId.json', {}, {
query: {method:'GET', params:{phoneId:'phones'}, isArray:true}
});
});
</pre>
__`app/js/controllers.js`.__
<pre>
function PhonesCtrl($route) {
var self = this;
$route.when('/phones',
{template:'partials/phone-list.html', controller:PhoneListCtrl});
$route.when('/phones/:phoneId',
{template:'partials/phone-detail.html', controller:PhoneDetailCtrl});
$route.otherwise({redirectTo:'/phones'});
$route.onChange(function(){
self.params = $route.current.params;
});
$route.parent(this);
}
//PhonesCtrl.$inject = ['$route'];
function PhoneListCtrl(Phone) {
this.orderProp = 'age';
this.phones = Phone.query();
}
//PhoneListCtrl.$inject = ['Phone'];
function PhoneDetailCtrl(Phone) {
this.phone = Phone.get({phoneId:this.params.phoneId});
}
//PhoneDetailCtrl.$inject = ['Phone'];
</pre>
## Discussion:
* We simplified our sub-controllers (`PhoneListCtrl` and `PhoneDetailCtrl`) by factoring out the
lower-level `$xhr` service, replacing it with a new service called `Phone`. Angular's {@link
angular.service.$resource `$resource`} service is easier to use than `$xhr` for interacting with
data sources exposed as RESTful resources. It is also easier now to understand what the code in
our controllers is doing.
* Once again we make use of `$route's` params, this time to construct the URL passed as a
parameter to `$resource` in our `services.js` script.
There you have it! We have created a web app in a relatively short amount of time.
## Closing Notes:
* For more details and examples of the angular concepts we touched on in this tutorial, see the
{@link guide Developer Guide}.
* For several more examples of sample code, see the {@link cookbook Cookbook}.
* When you are ready to start developing a project using angular, be sure to begin with the {@link
https://github.com/angular/angular-seed angular seed app}.
* We hope this tutorial was useful to you, and that you learned enough about angular to make you
want to learn more. Of course, we especially hope you are inspired to go out and develop angular
web apps of your own, and perhaps you might even be interested in {@link contribute contributing}
to angular.
<table id="tutorial_nav">
<tr>
<td id="previous_step">{@link tutorial.step_10 Previous}</td>
<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-11/app Example}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
<td id="code_diff">{@link
https://github.com/angular/angular-phonecat/commit/46e2bc3ff21a1385d6ef1860c5c242f8e0265379 Code
Diff}</td>
<td id="next_step">Next</td>
</tr>
</table>

133
docs/tutorial.step_2.ngdoc Executable file
View file

@ -0,0 +1,133 @@
@workInProgress
@ngdoc overview
@name Tutorial: Step 2
@description
<table id="tutorial_nav">
<tr>
<td id="previous_step">{@link tutorial.step_1 Previous}</td>
<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-2/app Example}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
<td id="code_diff">{@link
https://github.com/angular/angular-phonecat/commit/02e30dd64e0e5554fbf4d442ade5b1a251f2bf56
Code Diff}</td>
<td id="next_step">{@link tutorial.step_3 Next}</td>
</tr>
</table>
An important feature of angular is the incorporation of the principles behind {@link
http://en.wikipedia.org/wiki/ModelViewController the MVC design pattern} into client-side web
apps. With that in mind, let's use a little angular and a little JavaScript to add Model, View,
and Controller components to our app.
Our __View__ component is constructed by angular from this template:
__`app/index.html`:__
<pre>
...
<body ng:controller="PhoneListCtrl">
<ul>
<li ng:repeat="phone in phones">
{{phone.name}}
<p>{{phone.snippet}}</p>
</li>
</ul>
<script src="lib/angular/angular.js" ng:autobind></script>
<script src="js/controllers.js"></script>
</body>
...
</pre>
Our data __Model__ (a small set of phones in object literal notation) is instantiated within our
__Controller__ function (`PhoneListCtrl`):
__`app/js/controllers.js`:__
<pre>
/* App Controllers */
function PhoneListCtrl() {
this.phones = [{"name": "Nexus S",
"snippet": "Fast just got faster with Nexus S."},
{"name": "Motorola XOOM™ with Wi-Fi",
"snippet": "The Next, Next Generation tablet."},
{"name": "MOTOROLA XOOM™",
"snippet": "The Next, Next Generation tablet."}];
}
</pre>
The "Angular way" urges us to test as we develop:
__`test/unit/controllersSpec.js`:__
<pre>
/* jasmine specs for controllers go here */
describe('PhoneCat controllers', function() {
describe('PhoneListCtrl', function(){
it('should create "phones" model with 3 phones', function() {
var ctrl = new PhoneListCtrl();
expect(ctrl.phones.length).toBe(3);
});
});
});
</pre>
## Discussion:
So what were our changes from Step 1?
* __View template:__ We replaced the hard-coded phone list with the {@link
angular.widget.@ng:repeat ng:repeat widget} and two {@link guide.expression angular expressions}
enclosed in curly braces: `{{phone.name}}` and `{{phone.snippet}}`:
* The `ng:repeat="phone in phones"` statement in the `<li>` tag is an angular repeater. It
tells angular to create a `<li>` element for each phone in the phones list, using the first
`<li>` tag as the template.
* The curly braces around `phone.name` and `phone.snippet` are an example of {@link
angular.markup angular markup}. The curly braces are shorthand for the angular directive
{@link angular.directive.ng:bind ng:bind}. They indicate to angular that these are template
binding points. Binding points are locations in the template where angular constructs two-way
data-binding between the View and the Model. In angular, the View is a projection of the Model
through the HTML template.
* __Controller:__ At this point, it doesn't appear as if our controller is doing very much
controlling, but it is playing a crucial role: providing context for our data model so we can
establish two-way data-binding between the model and the view. Note in the following how we
connected the dots between our presentation, data, and logic components:
* The name of our controller function (in the JavaScript file `controllers.js`) matches the
{@link angular.directive.ng:controller ng:controller} directive in the `<body>` tag
(`PhoneListCtrl`).
* We instantiated our data within the scope of our controller function, and our template
binding points are located within the block bounded by the `<body
ng:controller="PhoneListCtrl>` tag.
So, our controller function becomes the {@link angular.scope scope} of our data model.
Angular uses scopes, along with the information contained in the template, data model, and
controller to keep the Model and View separated but in sync: any changes to the model are
reflected in the view; any changes that occur in the view are reflected in the model.
* __Model:__ For our data model, we created a simple array of phone records, specified in object
literal notation.
* __Testing:__ Ease of testing is another cornerstone of angular's design philosophy. All we are
doing here is showing how easy it is to create a unit test using the technology baked into
angular. The test verifies that we have some data, and that there are 3 records in the data set.
Angular's testing stack utilizes Jasmine's Behavior-driven Development (BDD) framework. You
can learn about it on the {@link http://pivotal.github.com/jasmine/ Jasmine home page} and on
the {@link https://github.com/pivotal/jasmine/wiki Jasmine wiki}.
<table id="tutorial_nav">
<tr>
<td id="previous_step">{@link tutorial.step_1 Previous}</td>
<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-2/app Example}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
<td id="code_diff">{@link
https://github.com/angular/angular-phonecat/commit/02e30dd64e0e5554fbf4d442ade5b1a251f2bf56
Code Diff}</td>
<td id="next_step">{@link tutorial.step_3 Next}</td>
</tr>
</table>

104
docs/tutorial.step_3.ngdoc Executable file
View file

@ -0,0 +1,104 @@
@workInProgress
@ngdoc overview
@name Tutorial: Step 3
@description
<table id="tutorial_nav">
<tr>
<td id="previous_step">{@link tutorial.step_2 Previous}</td>
<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-3/app Example}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
<td id="code_diff">{@link
https://github.com/angular/angular-phonecat/commit/a03815f8fb00217f5f9c1d3ef83282f79818e706 Code
Diff}</td>
<td id="next_step">{@link tutorial.step_4 Next}</td>
</tr>
</table>
In this step, we will add full text search to our app. We will also write an end-to-end test,
because a good end-to-end test is a good friend. It stays with your app, keeps an eye on it, and
quickly detects regressions.
__`app/index.html`:__
<pre>
...
Fulltext Search: <input name="query"/>
<ul class="phones">
<li ng:repeat="phone in phones.$filter(query)">
{{phone.name}}
<p>{{phone.snippet}}</p>
</li>
</ul>
...
</pre>
__`test/e2e/scenarios.js`:__
<pre>
/* jasmine-like end2end tests go here */
describe('PhoneCat App', function() {
describe('Phone list view', function() {
beforeEach(function() {
browser().navigateTo('../../app/index.html');
});
it('should filter the phone list as user types into the search box', function() {
expect(repeater('.phones li').count()).toBe(3);
input('query').enter('nexus');
expect(repeater('.phones li').count()).toBe(1);
input('query').enter('motorola');
expect(repeater('.phones li').count()).toBe(2);
});
});
});
</pre>
## Discussion:
We continued using the same controller that we set up in Step 2, but we added the following
features to our app:
* __Search Box:__ A standard HTML `<input>` tag combined with angular's {@link
angular.Array.filter $filter} utility (added to the repeater) lets a user type in search criteria
and immediately see the effects of their search on the phone list. This new code demonstrates the
following:
* Two-way data-binding. This is one of the very nice features in angular. In this example,
the data that you type into the input box (named __`query`__) is immediately available as a
filter in the list repeater (`phone in phones.$filter(`__`query`__`)`). When the page loads,
angular binds the name of the input box to a variable of the same name in the data model.
Whenever the data Model changes, the View reflects the change, and vice versa.
* Use of `$filter` in a template. The `$filter` function is one of several built-in utility
functions that augment JavaScript arrays during their evaluation as angular expressions. An
{@link Angular.array angular array} is a JavaScript array object with additional functionality
added. In {@link guide.expression angular expressions}, these array utilities are available as
methods. (They are prefixed with a $ to avoid naming collisions.)
* How `ng:repeat` automatically shrinks and grows the number of phones in the View, via DOM
manipulation that is completely transparent to the developer. If you've written any DOM
manipulation code, this should make you happy.
* __CSS:__ We added in some minimal CSS to the file we set up in Step 0: `./css/app.css`.
* __Testing:__ This end-to-end test shows the following:
* Proof that the search box and the repeater are correctly wired together.
* How easy it is to write end-to-end tests. This is just a simple test, but the point here is
to show how easy it is to set up a functional, readable, end-to-end test.
<table id="tutorial_nav">
<tr>
<td id="previous_step">{@link tutorial.step_2 Previous}</td>
<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-3/app Example}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
<td id="code_diff">{@link
https://github.com/angular/angular-phonecat/commit/a03815f8fb00217f5f9c1d3ef83282f79818e706 Code
Diff}</td>
<td id="next_step">{@link tutorial.step_4 Next}</td>
</tr>
</table>

114
docs/tutorial.step_4.ngdoc Executable file
View file

@ -0,0 +1,114 @@
@workInProgress
@ngdoc overview
@name Tutorial: Step 4
@description
<table id="tutorial_nav">
<tr>
<td id="previous_step">{@link tutorial.step_3 Previous}</td>
<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-4/app Example}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
<td id="code_diff">{@link
https://github.com/angular/angular-phonecat/commit/b56c91f453114347f0cb25e70b1c4fa4f1421763 Code
Diff}</td>
<td id="next_step">{@link tutorial.step_5 Next}</td>
</tr>
</table>
In this step, we add a feature that lets our users choose which way to order the phone list.
__`app/index.html`:__
<pre>
...
<ul class="predicates">
<li>
Search: <input type="text" name="query"/>
</li>
<li>
Sort by:
<select name="orderProp">
<option value="name">Alphabetical</option>
<option value="age">Newest</option>
</select>
</li>
</ul>
<ul class="phones">
<li ng:repeat="phone in phones.$filter(query).$orderBy(orderProp)">
{{phone.name}}
<p>{{phone.snippet}}</p>
</li>
</ul>
...
</pre>
__`app/js/controller.js`:__
<pre>
/* App Controllers */
function PhoneListCtrl() {
this.phones = [{"name": "Nexus S",
"snippet": "Fast just got faster with Nexus S.",
"age": 0},
{"name": "Motorola XOOM™ with Wi-Fi",
"snippet": "The Next, Next Generation tablet.",
"age": 1},
{"name": "MOTOROLA XOOM™",
"snippet": "The Next, Next Generation tablet.",
"age": 2}];
this.orderProp = 'age';
}
</pre>
__`test/unit/controllerSpec.js`:__
<pre>
/* jasmine specs for controllers go here */
describe('PhoneCat controllers', function() {
describe('PhoneListCtrl', function(){
var scope, $browser, ctrl;
beforeEach(function() {
ctrl = new PhoneListCtrl();
});
it('should create "phones" model with 3 phones', function() {
expect(ctrl.phones.length).toBe(3);
});
it('should set the default value of orderProp model', function() {
expect(ctrl.orderProp).toBe('age');
});
});
});
</pre>
## Discussion:
To provide dynamic ordering, we employ another one of angular's "array type augmenters" and let
the data binding do the rest of the work for us:
* Like {@link angular.Array.filter $filter}, {@link angular.Array.orderBy $orderBy} is a built-in
method available on array objects in angular expressions. In our UI template, we set up a select
box that lets the user set the `orderProp` model variable to one of the string constants: `age` or
`name`.
* In our controller, we added a line to set the default value of `orderProp` to `age`.
* Our unit test now verifies that our default ordering property is set.
* Once again we added a little more CSS to improve the View.
<table id="tutorial_nav">
<tr>
<td id="previous_step">{@link tutorial.step_3 Previous}</td>
<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-4/app Example}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
<td id="code_diff">{@link
https://github.com/angular/angular-phonecat/commit/b56c91f453114347f0cb25e70b1c4fa4f1421763 Code
Diff}</td>
<td id="next_step">{@link tutorial.step_5 Next}</td>
</tr>
</table>

109
docs/tutorial.step_5.ngdoc Executable file
View file

@ -0,0 +1,109 @@
@workInProgress
@ngdoc overview
@name Tutorial: Step 5
@description
<table id="tutorial_nav">
<tr>
<td id="previous_step">{@link tutorial.step_4 Previous}</td>
<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-5/app Example}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
<td id="code_diff">{@link
https://github.com/angular/angular-phonecat/commit/4f0a518557b5c7442568666b211aa79499870276 Code
Diff}</td>
<td id="next_step">{@link tutorial.step_6 Next}</td>
</tr>
</table>
In this step, the View template remains the same but the Model and Controller change. We'll
introduce the use of an angular {@link angular.service service}, which we will use to implement an
`HttpXmlRequest` request to communicate with a server. Angular provides the built-in {@link
angular.service.$xhr $xhr} service for this purpose.
The addition of the `$xhr` service to our app gives us the opportunity to talk about {@link
guide.di Dependency Injection} (DI). The use of DI is another cornerstone of the angular
philosophy. DI helps make your web apps well structured, loosely coupled, and ultimately easier to
test.
__`app/js/controllers.js:`__
<pre>
/* App Controllers */
function PhoneListCtrl($xhr) {
var self = this;
$xhr('GET', 'phones/phones.json', function(code, response) {
self.phones = response;
});
self.orderProp = 'age';
}
//PhoneListCtrl.$inject = ['$xhr'];
</pre>
__`test/unit/controllerSpec.js`:__
<pre>
/* jasmine specs for controllers go here */
describe('PhoneCat controllers', function() {
describe('PhoneListCtrl', function(){
var scope, $browser, ctrl;
beforeEach(function() {
scope = angular.scope();
$browser = scope.$service('$browser');
$browser.xhr.expectGET('phones/phones.json').respond([{name: 'Nexus S'},
{name: 'Motorola DROID'}]);
ctrl = scope.$new(PhoneListCtrl);
});
it('should create "phones" model with 2 phones fetched from xhr', function() {
expect(ctrl.phones).toBeUndefined();
$browser.xhr.flush();
expect(ctrl.phones).toEqual([{name: 'Nexus S'},
{name: 'Motorola DROID'}]);
});
it('should set the default value of orderProp model', function() {
expect(ctrl.orderProp).toBe('age');
});
});
});
</pre>
## Discussion:
* __Services:__ {@link angular.service Services} are substitutable objects managed by angular's
{@link guide.di DI subsystem}. Angular services simplify some of the standard operations common
to web apps. Angular provides several built-in services (such as {@link angular.service.$xhr
$xhr}). You can also create your own custom services.
* __Dependency Injection:__ To use an angular service, you simply provide the name of the service
as a parameter to the function in which you are using that service. Angular's {@link guide.di DI
subsystem} recognizes the identity of the service by name, provides it for you when you need it,
and manages any transitive dependencies the service may have (services often depend upon other
services).
* __`$xhr`:__ We moved our data set out of the controller and into the file `phones/phones.json`.
This file serves as our data store rather than an actual server (to the browser they look the
same). We now use the `$xhr` service to return our phone data, which you'll note is still within
the scope of our controller function.
* __Testing:__ The unit test has been expanded. It now verifies that the `$xhr` service behaves
as expected.
<table id="tutorial_nav">
<tr>
<td id="previous_step">{@link tutorial.step_4 Previous}</td>
<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-5/app Example}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
<td id="code_diff">{@link
https://github.com/angular/angular-phonecat/commit/4f0a518557b5c7442568666b211aa79499870276 Code
Diff}</td>
<td id="next_step">{@link tutorial.step_6 Next}</td>
</tr>
</table>

101
docs/tutorial.step_6.ngdoc Executable file
View file

@ -0,0 +1,101 @@
@workInProgress
@ngdoc overview
@name Tutorial: Step 6
@description
<table id="tutorial_nav">
<tr>
<td id="previous_step">{@link tutorial.step_5 Previous}</td>
<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-6/app Example}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
<td id="code_diff">{@link
https://github.com/angular/angular-phonecat/commit/2fb113a4da9b6d19e17627f351f0681befcccdc0 Code
Diff}</td>
<td id="next_step">{@link tutorial.step_7 Next}</td>
</tr>
</table>
In this step, we add thumbnail images, links, and a little more CSS to our app. For now, our
links go nowhere. One step at a time; in the next step we'll implement new views that these links
will open.
__`app/index.html`:__
<pre>
...
<ul class="predicates">
<li>
Search: <input type="text" name="query"/>
</li>
<li>
Sort by:
<select name="orderProp">
<option value="name">Alphabetical</option>
<option value="age">Newest</option>
</select>
</li>
</ul>
<ul class="phones">
<li ng:repeat="phone in phones.$filter(query).$orderBy(orderProp)">
<a href="#/phones/{{phone.id}}">{{phone.name}}</a>
<a href="#/phones/{{phone.id}}" class="thumb"><img ng:src="{{phone.imageUrl}}"></a>
<p>{{phone.snippet}}</p>
</li>
</ul>
...
</pre>
__`app/js/controller.js`__ (Unchanged):
<pre>
/* App Controllers */
function PhoneListCtrl($xhr) {
var self = this;
$xhr('GET', 'phones/phones.json', function(code, response) {
self.phones = response;
});
self.orderProp = 'age';
}
//PhoneListCtrl.$inject = ['$xhr'];
</pre>
__`app/phones/phones.json`__ (sample snippet):
<pre>
[
{
"age": 4,
...
"carrier": "T-Mobile",
"id": "motorola-defy-with-motoblur",
"imageUrl": "http://google.com/phone/image/small/640001",
"name": "Motorola DEFY\u2122 with MOTOBLUR\u2122",
"snippet": "Are you ready for everything life throws your way?"
},
]
</pre>
## Discussion:
* Note that we're using {@link guide.expression angular expressions} enclosed in the now-familiar
{@link angular.markup double-curly brace markup} in the href attribute values. These represent
attribute bindings, and work the same way as the bindings we saw in previous steps.
* Note also the use of the {@link angular.directive.ng:src ng:src} directive in the `<img>` tag.
That directive prevents the browser from treating the angular `{{ exppression }}` markup
literally, as it would do if we tried to use markup in a regular `src` attribute. Use `ng:src` to
keep the browser from eagerly making an extra http request to an invalid location.
<table id="tutorial_nav">
<tr>
<td id="previous_step">{@link tutorial.step_5 Previous}</td>
<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-6/app Example}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
<td id="code_diff">{@link
https://github.com/angular/angular-phonecat/commit/2fb113a4da9b6d19e17627f351f0681befcccdc0 Code
Diff}</td>
<td id="next_step">{@link tutorial.step_7 Next}</td>
</tr>
</table>

159
docs/tutorial.step_7.ngdoc Executable file
View file

@ -0,0 +1,159 @@
@workInProgress
@ngdoc overview
@name Tutorial: Step 7
@description
<table id="tutorial_nav">
<tr>
<td id="previous_step">{@link tutorial.step_6 Previous}</td>
<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-7/app Example}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
<td id="code_diff">{@link
https://github.com/angular/angular-phonecat/commit/43ff5d76f1c0a464da67d691418e33e6c9d8dbc8 Code
Diff}</td>
<td id="next_step">{@link tutorial.step_8 Next}</td>
</tr>
</table>
In this step we introduce angular's {@link angular.service.$route $route} service. This service
is usually used in conjunction with the {@link angular.widget.ng:view ng:view} directive. The
`$route` service makes it easy to wire together controllers, View templates, and the current URL
location in the browser. Using this feature we can implement {@link
http://en.wikipedia.org/wiki/Deep_linking deep linking}, which lets us utilize the browser's
History, and Back and Forward browser navigation.
We'll use {@link angular.service.$route $route} to implement two different views for our
application: one view presents the phone listing, and the other view presents the details for a
particular phone. We'll use {@link angular.widget.ng:view ng:view} to include one or the other of
those views in our main layout page (`index.html`). The view presented in the layout page is based
on which URL the user navigates to.
To manage our two different views, we'll move the existing phone list controller into a
sub-controller, add a second sub-controller to handle the phone details, and we'll create a new
root controller to implement the routing. (We'll save the implementation of the phone details
View for the next step.)
__`app/index.html`:__
<pre>
<body ng:controller="PhoneCatCtrl">
...
<ng:view></ng:view>
...
</pre>
__`app/partials/phone-list.html`:__
<pre>
<ul class="predicates">
<li>
Search: <input type="text" name="query"/>
</li>
<li>
Sort by:
<select name="orderProp">
<option value="name">Alphabetical</option>
<option value="age">Newest</option>
</select>
</li>
</ul>
<ul class="phones">
<li ng:repeat="phone in phones.$filter(query).$orderBy(orderProp)">
<a href="#/phones/{{phone.id}}">{{phone.name}}</a>
<a href="#/phones/{{phone.id}}" class="thumb"><img ng:src="{{phone.imageUrl}}"></a>
<p>{{phone.snippet}}</p>
</li>
</ul>
</pre>
__`app/js/controller.js`:__
<pre>
/* App Controllers */
function PhoneCatCtrl($route) {
var self = this;
$route.when('/phones',
{template: 'partials/phone-list.html', controller: PhoneListCtrl});
$route.when('/phones/:phoneId',
{template: 'partials/phone-detail.html', controller: PhoneDetailCtrl});
$route.otherwise({redirectTo: '/phones'});
$route.onChange(function(){
self.params = $route.current.params;
});
$route.parent(this);
}
//PhoneCatCtrl.$inject = ['$route'];
function PhoneListCtrl($xhr) {
var self = this;
$xhr('GET', 'phones/phones.json', function(code, response) {
self.phones = response;
});
self.orderProp = 'age';
}
//PhoneListCtrl.$inject = ['$xhr'];
function PhoneDetailCtrl() {}
</pre>
## Discussion:
We have many changes to discuss here in Step 7:
* __The View.__ Our View template in `index.html` has been reduced down to this:
`<ng:view></ng:view>`. It is now what we call a "layout template", because it contains
information common for all views, including the layout of our application. The {@link
angular.widget.ng:view ng:view} directive behaves like an "include" declaration (it's a
specialized sibling of the {@link angular.widget.ng:include ng:include} directive) that works
specifically with the {@link angular.service.$route $route} service. The View template associated
with the current route definition gets included "between those tags" (there's more to it than a
simple include, but that explanation will do for now).
* We added two new View templates:
* `app/partials/phone-list.html` for the phone list;
* `app/partials/phone-detail.html` for the phone details (just a stub for this step);
* __The Controller(s).__ We now have a new root controller (`PhoneCatCtrl`) and two
sub-controllers (`PhoneListCtrl` and `PhoneDetailCtrl`).
* __`$route.`__ The root controller's job now is to set up the `$route` configuration:
* When the fragment part of the URL in the browser ends in "/phones", `$route` grabs the
`phone-list.html` template, compiles it, and links it with a new scope that is controlled
by our `PhoneListCtrl` controller.
* When the URL ends in "/phones/:phoneId", `$route` compiles and links the
`phone-detail.html` template as it did with `phone-list.html`. But note the use of the
variable `:phoneId` in the `path` parameter of `$route.when()`: `$route` stores that
portion of the current URL fragment in its current parameters in a property called
`params.phoneId`. We made the `$route` parameters available to our sub-controllers in the
`$route.onChange()` function in our root controller. We will use the `phoneId` property
when we fetch the phone details in Step 8.
* Any other URL fragment gets redirected to `/phones`.
* __Deep Linking.__ In `$route`'s `onChange()` method, we copied {@link
http://en.wikipedia.org/wiki/Deep_linking deep linking} parameters to the `params` property in
the root scope, so we can use them in the child scopes managed by our sub-controllers.
<table id="tutorial_nav">
<tr>
<td id="previous_step">{@link tutorial.step_6 Previous}</td>
<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-7/app Example}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
<td id="code_diff">{@link
https://github.com/angular/angular-phonecat/commit/43ff5d76f1c0a464da67d691418e33e6c9d8dbc8 Code
Diff}</td>
<td id="next_step">{@link tutorial.step_8 Next}</td>
</tr>
</table>

110
docs/tutorial.step_8.ngdoc Executable file
View file

@ -0,0 +1,110 @@
@workInProgress
@ngdoc overview
@name Tutorial: Step 8
@description
<table id="tutorial_nav">
<tr>
<td id="previous_step">{@link tutorial.step_7 Previous}</td>
<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-8/app Example}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
<td id="code_diff">{@link
https://github.com/angular/angular-phonecat/commit/1f91f571bdd6f1e705ebb303998afe7820ffc6d9 Code
Diff}</td>
<td id="next_step">{@link tutorial.step_9 Next}</td>
</tr>
</table>
In this step, we implement the Phone Details View template. Once again we will use {@link
angular.services.$xhr $xhr} to fetch our data, and we'll flesh out the `phone-details.html` View
template.
__`app/partials/phone-details.html`:__
<pre>
<img ng:src="{{phone.images[0]}}" class="phone"/>
<h1>{{phone.name}}</h1>
<p>{{phone.description}}</p>
<ul class="phone-thumbs">
<li ng:repeat="img in phone.images">
<img ng:src="{{img}}"/>
</li>
</ul>
<ul class="specs">
<li>
<span>Availability and Networks</span>
<dl>
<dt>Availability</dt>
<dd ng:repeat="availability in phone.availability">{{availability}}</dd>
</dl>
</li>
...
<span>Additional Features</span>
<dd>{{phone.additionalFeatures}}</dd>
</li>
</ul>
</pre>
__`app/js/controller.js`:__
<pre>
function PhoneCatCtrl($route) (same as Step 7)
function PhoneListCtrl($xhr) (same as Step 7)
function PhoneDetailCtrl($xhr) {
var self = this;
$xhr('GET', 'phones/' + self.params.phoneId + '.json', function(code, response) {
self.phone = response;
});
}
//PhoneDetailCtrl.$inject = ['$xhr'];
</pre>
__`app/phones/nexus-s.json`:__ (sample snippet)
<pre>
{
"additionalFeatures": "Contour Display, Near Field Communications (NFC), Three-axis gyroscope,
Anti-fingerprint display coating, Internet Calling support (VoIP/SIP)",
"android": {
"os": "Android 2.3",
"ui": "Android"
},
...
"images": [
"img/phones/nexus-s.0.jpg",
"img/phones/nexus-s.1.jpg",
"img/phones/nexus-s.2.jpg",
"img/phones/nexus-s.3.jpg"
],
"storage": {
"flash": "16384MB",
"ram": "512MB"
}
}
</pre>
## Discussion:
* Phone Details View Template. There is nothing fancy or new here, just note where we use the
angular `{{ expression }}` markup and directives to project phone data from our model.
* Note how we used the `$route` `params` object from the scope managed by the root controller
(`PhoneCatCtrl`), to construct the path to the phone details requested by the user. The rest of
this step is simply applying the previously learned concepts and angular APIs to create a large
template that displays a lot of data about a phone.
<table id="tutorial_nav">
<tr>
<td id="previous_step">{@link tutorial.step_7 Previous}</td>
<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-8/app Example}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
<td id="code_diff">{@link
https://github.com/angular/angular-phonecat/commit/1f91f571bdd6f1e705ebb303998afe7820ffc6d9 Code
Diff}</td>
<td id="next_step">{@link tutorial.step_9 Next}</td>
</tr>
</table>

95
docs/tutorial.step_9.ngdoc Executable file
View file

@ -0,0 +1,95 @@
@workInProgress
@ngdoc overview
@name Tutorial: Step 9
@description
<table id="tutorial_nav">
<tr>
<td id="previous_step">{@link tutorial.step_8 Previous}</td>
<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-9/app Example}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
<td id="code_diff">{@link
https://github.com/angular/angular-phonecat/commit/975d173ad0768487852387497c086f3c93fb48f6 Code
Diff}</td>
<td id="next_step">{@link tutorial.step_10 Next}</td>
</tr>
</table>
In this step, we have determined that the built-in angular display filters ({@link
angular.filter.number number}, {@link angular.filter.currency currency}, {@link
angular.filter.date date}, etc.) do not handle what we want to do, and so we get to create our own
custom {@link angular.filter filter}.
In the previous step, the details page displayed either "true" or "false" to indicate whether
certain phone features were present or not. Our custom "checkmark" filter replaces those text
strings with images: ✓ for "true", and ✘ for "false".
Our filter code lives in `app/js/filters.js`:
__`app/index.html`.__
<pre>
...
<script src="app/js/filters.js"></script>
...
</pre>
In the phone details template, we employ our filter for angular expressions whose values are
"true" or "false"; `{{ [phone_feature] | checkmark }}`:
__`app/partials/phone-detail.html`.__
<pre>
<img ng:src="{{phone.images[0].large}}" class="phone"/>
<h1>{{phone.name}}</h1>
<p>{{phone.description}}</p>
...
<ul class="specs">
...
<li>
<span>Connectivity</span>
<dl>
<dt>Network Support</dt>
<dd>{{phone.connectivity.cell}}</dd>
<dt>WiFi</dt>
<dd>{{phone.connectivity.wifi}}</dd>
<dt>Bluetooth</dt>
<dd>{{phone.connectivity.bluetooth}}</dd>
<dt>Infrared</dt>
<dd>{{phone.connectivity.infrared | checkmark}}</dd>
<dt>GPS</dt>
<dd>{{phone.connectivity.gps | checkmark}}</dd>
</dl>
</li>
...
</ul>
</pre>
__`app/js/filters.js`.__ (New)
<pre>
/* http://docs.angularjs.org/#!angular.filter */
angular.filter('checkmark', function(input) {
return input ? '\u2713' : '\u2718';
});
</pre>
## Discussion:
This example shows how easy it is to roll your own filters for displaying data. As explained in
the "Writing your own Filters" section of the {@link angular.filter angular.filter} page, you
simply add your filter function on to the `angular.filter` object.
In this example, our filter name is "checkmark"; our input is either "true" or "false", and we
return one of two unicode characters we have chosen to represent true or false (`\u2713` and
`\u2718`).
<table id="tutorial_nav">
<tr>
<td id="previous_step">{@link tutorial.step_8 Previous}</td>
<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-9/app Example}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
<td id="code_diff">{@link
https://github.com/angular/angular-phonecat/commit/975d173ad0768487852387497c086f3c93fb48f6 Code
Diff}</td>
<td id="next_step">{@link tutorial.step_10 Next}</td>
</tr>
</table>

155
docs/tutorial_intro.ngdoc Normal file
View file

@ -0,0 +1,155 @@
@workInProgress
@ngdoc overview
@name Intro to Tutorial
@description
A great way to get introduced to angular is to work through the {@link Tutorial angular tutorial},
which walks you through the construction of an angular web app. The app you will build in the
tutorial is based on the {@link http://www.google.com/phone/# Google phone gallery app}.
Once you set up your tutorial environment, you should be able to get through the material in less
than a day and you'll have fun doing it. More experienced coders may be able to zip through the
exercises in an afternoon. In any case, we promise that your time will be well spent!
When you finish the tutorial you will be able to:
* Create a simple dynamic application that works in any browser
* Define the differences between angular and common JavaScript frameworks
* Understand angular expressions
* Understand how data binding works in angular
* Create your own angular widgets and directives
* Add your own tags to angular
* Use the angular-seed project to quickly boot-strap your own projects
* Create and run tests
* Identify resources for learning more about angular
You can work through the tutorial in any of the following ways:
* <a href="#UsingGit">Using Git</a>. Use the Git Versioning System to get the files for each step.
* <a href="#UsingSnapshots">Using Snapshots</a>. Download snapshots (files for each step of the
tutorial) from the angular server.
* <a href="#ReadingExamples">Reading the Examples</a>. Read through the examples, and inspect
results and code on our server.
The first two ways (Git and snapshots) give you a fuller experience, in that you can run the unit
and end-to-end tests in addition to the tutorial app. They also give you the ability to play
around with the code and get instant feedback in your browser. The last way (reading through the
tutorial online) requires no setup on your machine, but you can't run the tests, and it won't be
as easy to play around with the code.
<a name="PreReqs"></a>
# Prerequisites for Git and Snapshots
To run the tutorial app and tests on your machine (using Git or the snapshots) you will need the
following:
* An http server running on your system. If you don't already have one installed, you can install
`node.js` ({@link https://github.com/joyent/node/wiki/Installation node.js install}) or another
http sever (such as Apache, etc.).
* Java. This is required for running tests. Angular itself doesn't require Java.
* A modern browser. Needed for viewing and debugging code.
* A text editor of your choice.
<a name="UsingGit"></a>
# Using Git
The following instructions are for developers who are comfortable with Git's versioning system:
1. Check to be sure you have all of the <a href="#PreReqs">prerequisites</a> on your system.
1. Clone the angular-phonecat repository located at {@link
https://github.com/angular/angular-phonecat angular-phonecat} by running the following command in
a terminal:
git clone git://github.com/angular/angular-phonecat.git
This will create a directory called `angular-phonecat`.
1. In terminal, navigate to the `angular-phonecat` directory and run:
git checkout step-0
(You can run `git checkout step-[0-11]` to go to any of the steps in the tutorial).
1. To see the app running in your browser, do the following:
* __For node.js users:__
1. Run `./scripts/web-server.js` to start the web server.
1. Open a browser window for the app and navigate to http://localhost:8000/app/index.html.
1. Open a browser window for the tests, navigate to http://localhost:9876, and choose
"strict mode".
* __For other http servers:__
1. Configure the server to serve the files in the `angular-phonecat` directory.
1. Start the server.
1. Navigate in your browser to
http://localhost:[*port-number*]/[*context-path*]/app/index.html.
1. Navigate in your browser to http://localhost:[*port-number*]/, and choose "strict mode".
<a name="UsingSnapshots"></a>
# Using Snapshots
Snapshots are the sets of files that reflect the state of the tutorial app at each step. These
files include the HTML, CSS, and JavaScript for the app, plus Jasmine JavaScript files and Java
libraries for the test stack. These will let you run the tutorial app and tests, without requiring
knowledge of Git. You can download and install the snapshot files as follows:
1. Check to be sure you have all of the <a href="#PreReqs">prerequisites</a> on your system.
1. Navigate to [*the angular server*].
1. Download and unzip [*the snapshot file*] to a suitable location.
1. Change directories to [*install-dir*]/sandbox.
1. Run the following command:
* `./goto_step.sh 0`
You have to start out at the beginning, which is Step 0. After you set up Step 0, you can skip
around between any steps.
1. To see the app running in your browser, do the following:
* __For node.js users:__
1. Run `./scripts/web-server.js` to run the web server.
1. Open a browser window for the app and navigate to http://localhost:8000/app/index.html.
1. Open a browser window for the tests, navigate to http://localhost:9876, and choose
"strict mode".
* __For other http servers:__
1. Configure servers to serve the app and test files in the [*install-dir*]/sandbox.
1. Start the server.
1. Navigate in your app browser to
http://localhost:[*port-number*]/[*context-path*]/app/index.html.
1. Navigate in your test browser to http://localhost:[*port-number*] and choose "strict
mode".
1. To view the tutorial app at different steps, run `./goto_step.sh [0-11]` and then refresh your
browser. For example, say you're on Step 5 of the tutorial, and you want to see the app in action:
1. Run `goto_step.sh 5` from the command line in the `sandbox` directory.
1. Refresh your app browser.
<a name="ReadingExamples"></a>
# Reading the Examples
If you don't want to set up anything on your local machine, you can read through {@link Tutorial
the tutorial} and inspect the tutorial files on our servers; doing this will give you a good idea
of what angular does.
To see the running app at each tutorial step, click the "Example" link at the top or bottom of
each tutorial page.
To view the code differences between tutorial steps, click the Code Diff link at top or bottom of
each tutorial page. Additions are highlighted in green; deletions are highlighted in red.
# Relative URLs
Throughout the tutorial, we use relative URLs to refer to files hosted on our local http server.
The absolute URL depends on your configuration. For example, if you are using the node.js server,
`app/index.html` translates to:
http://localhost:8000/app/index.html
If you are using your own http server running on port 8080 and the tutorial files are hosted at
`/angular_tutorial`, `app/index.html` translates to:
http://localhost:8080/angular_tutorial/app/index.html