aboutsummaryrefslogtreecommitdiffstats
path: root/docs/content/tutorial/step_02.ngdoc
diff options
context:
space:
mode:
authorIgor Minar2011-05-10 17:45:42 -0700
committerIgor Minar2011-06-06 22:51:58 -0700
commit3751f172b3986604853700a1475a7ad81b42a9b1 (patch)
treef6bd09073a22e36b48a6c4454aa082d422a6fd92 /docs/content/tutorial/step_02.ngdoc
parent3776e08db08232d38b6d5e561092ef78795ec356 (diff)
downloadangular.js-3751f172b3986604853700a1475a7ad81b42a9b1.tar.bz2
add new batch of tutorial docs and images
Diffstat (limited to 'docs/content/tutorial/step_02.ngdoc')
-rwxr-xr-xdocs/content/tutorial/step_02.ngdoc171
1 files changed, 126 insertions, 45 deletions
diff --git a/docs/content/tutorial/step_02.ngdoc b/docs/content/tutorial/step_02.ngdoc
index fdf881b0..04b7b3e0 100755
--- a/docs/content/tutorial/step_02.ngdoc
+++ b/docs/content/tutorial/step_02.ngdoc
@@ -1,11 +1,11 @@
-@ngdoc overview
+@ngdoc overview
@name Tutorial: Step 2
@description
<table id="tutorial_nav">
<tr>
<td id="previous_step">{@link tutorial.step_01 Previous}</td>
<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-2/app Live
- Demo}</td>
+Demo}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
<td id="code_diff">{@link https://github.com/angular/angular-phonecat/compare/step-1...step-2 Code
Diff}</td>
@@ -13,39 +13,54 @@ Diff}</td>
</tr>
</table>
+
Now it's time to make this web page dynamic with angular. We'll also add a test that verifies the
-code for the controller we are going to add.
+code for the controller we are going to add.
+
+
+There are many ways to structure the code for an application. With angular, we encourage the use of
+{@link http://en.wikipedia.org/wiki/Model–View–Controller the MVC design pattern} to decouple 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.
-There are many ways to structure the code for an application. With angular, we encourage the use
-of {@link http://en.wikipedia.org/wiki/Model–View–Controller the MVC design pattern} to decouple
-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:
+ git checkout -f step-2
- git checkout --force step-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 angular's 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}:
+
+
## Template for the View
-The __View__ component is constructed by angular from this template:
+
+The __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}}
@@ -53,33 +68,44 @@ __`app/index.html`:__
</li>
</ul>
+
<script src="lib/angular/angular.js" ng:autobind></script>
<script src="js/controllers.js"></script>
</body>
</html>
</pre>
+
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}}`:
+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.
+tells angular to create a `<li>` element for each phone in the phones list, using the first `<li>`
+tag as the template.
+
+
+ <img src="img/tutorial/tutorial_02_final.png">
+
* The curly braces around `phone.name` and `phone.snippet` are an example of {@link
- 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.
+angular.markup angular markup}. The curly markup is shorthand for the angular directive {@link
+angular.directive.ng:bind ng:bind}. The `ng:bind` directives indicate to angular that these are
+template binding points. Binding points are locations in the template where angular creates
+data-binding between the view and the model. In angular, the view is a projection of the model
+through the HTML template. This means that whenever the model changes, angular refreshes the
+appropriate binding points, which updates the view.
+
+
## Model and Controller
-The data __Model__ (a short list of phones in object literal notation) is instantiated within the
-__Controller__ function (`PhoneListCtrl`):
+
+The data __model__ (a simple array of phones in object literal notation) is instantiated within
+the __controller__ function (`PhoneListCtrl`):
+
__`app/js/controllers.js`:__
<pre>
@@ -93,36 +119,52 @@ function PhoneListCtrl() {
}
</pre>
+
+
+
+
+
+
+
Although the controller is not yet doing very much controlling, it is playing a crucial role. By
providing context for our data model, the controller allows us to establish data-binding between
the model and the view. Note in the following how we connected the dots between our presentation,
-data, and logic components:
+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`).
+{@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.
+binding points are located within the block bounded by the `<body ng:controller="PhoneListCtrl">`
+tag.
+
+
+ Angular scopes are a crucial concept in angular; you can think of scopes as the glue that makes
+the template, model and controller all work together. 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. To learn more about angular scopes, see the {@link
+angular.scopes angular scope documentation}.
+
- 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.
-As for our data model, we created a simple array of phone records, specified in object literal
-notation.
## Tests
+
The "Angular way" makes it easy for us to test as we develop; the unit test for your newly created
controller looks as follows:
+
__`test/unit/controllersSpec.js`:__
<pre>
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);
@@ -131,78 +173,117 @@ describe('PhoneCat controllers', function() {
});
</pre>
+
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. The test verifies that we have 3 records in the
phones array.
-Angular developers prefer the syntax of Jasmine's Behavior-driven Development (BDD) framework when
+
+Angular developers prefer the syntax of Jasmine's Behavior-driven Development (BDD) framework when
writing tests. Although Jasmine is not required by angular, we used it to write all tests in this
-tutorial. You can learn about Jasmine on the {@link http://pivotal.github.com/jasmine/ Jasmine
-home page} and on the {@link https://github.com/pivotal/jasmine/wiki Jasmine wiki}.
+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}.
+
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.
-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`
+2. Open a new browser tab or window and navigate to {@link http://localhost:9876}.
+
+
+3. Choose "Capture this browser in strict mode".
+
+
+At this point, you can leave this tab open and forget about it. JsTestDriver will use it to execute
+the tests and report the results in the terminal.
+
+
+4. Execute the test by running `./scripts/test.sh`
+
You should see the following or similar output:
+
Chrome: Runner reset.
.
Total 1 tests (Passed: 1; Fails: 0; Errors: 0) (2.00 ms)
Chrome 11.0.696.57 Mac OS: Run 1 tests (Passed: 1; Fails: 0; Errors 0) (2.00 ms)
- Yay! The test passed!
+
+ Yay! The test passed! Or not...
+
+
+Note: If you see errors after you run the test, close the browser tab and go back to the terminal
+and kill the script, then repeat the procedure above.
+
# Experiments
-* Add another binding to `index.html`. For example:
+
+* 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!"
+
+ this.hello = "Hello, World!"
+
+
+Refresh your browser to make sure it says, "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">
<tr>
<td id="previous_step">{@link tutorial.step_01 Previous}</td>
<td id="step_result">{@link http://angular.github.com/angular-phonecat/step-2/app Live
- Demo}</td>
+Demo}</td>
<td id="tut_home">{@link tutorial Tutorial Home}</td>
<td id="code_diff">{@link https://github.com/angular/angular-phonecat/compare/step-1...step-2 Code
Diff}</td>
<td id="next_step">{@link tutorial.step_03 Next}</td>
</tr>
</table>
+
+
+