aboutsummaryrefslogtreecommitdiffstats
path: root/docs/tutorial.step_2.ngdoc
blob: f78cb2aa41c9995d66de4d74015d3b4a9246938b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
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>