| 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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
 | @workInProgress
@ngdoc overview
@name Tutorial: Step 4
@description
<table id="tutorial_nav">
<tr>
<td id="previous_step">{@link tutorial.step_03 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/compare/step-3...step-4 Code
Diff}</td>
<td id="next_step">{@link tutorial.step_05 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>
__`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);
    });
    it('should be possible to control phone order via the drop down select box', function() {
      input('query').enter('tablet'); //let's narrow the dataset to make the test assertions
      shorter
      expect(repeater('.phones li', 'Phone List').column('a')).
          toEqual(["Motorola XOOM\u2122 with Wi-Fi",
                   "MOTOROLA XOOM\u2122"]);
      select('orderProp').option('alphabetical');
      expect(repeater('.phones li', 'Phone List').column('a')).
          toEqual(["MOTOROLA XOOM\u2122",
                   "Motorola XOOM\u2122 with Wi-Fi"]);
    });
  });
});
</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:
* First, we provide a `<select>` element named `orderProp` for our users so they can choose to
sort the phone list either alphabetically or by the age of the phone.  We added the `age` property
to each phone record so we can sort by that field.
* 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`.  If we
don't override the default value, angular uses the value of the first `<option>` element when it
initializes the data model.
* Our unit test now verifies that our default ordering property is set.
* We added an end-to-end test to verify that our select box ordering mechanism works properly.
* Once again we added a little more CSS to improve the View.
<table id="tutorial_nav">
<tr>
<td id="previous_step">{@link tutorial.step_03 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/compare/step-3...step-4 Code
Diff}</td>
<td id="next_step">{@link tutorial.step_05 Next}</td>
</tr>
</table>
 |