请重置工作目录:

你应该发现除了搜索框之外,你的应用多了一个下来菜单,它可以允许控制电话排列的顺序。

步骤3和步骤4之间最重要的不同在下面列出。你可以在里看到完整的差别。

app/index.html

  1. Sort by:
  2. <select ng-model="orderProp">
  3. <option value="name">Alphabetical</option>
  4. <option value="age">Newest</option>
  5. </select>
  6. <ul class="phones">
  7. <li ng-repeat="phone in phones | filter:query | orderBy:orderProp">
  8. {{phone.name}}
  9. <p>{{phone.snippet}}</p>
  10. </li>
  11. </ul>

我们在index.html中做了如下更改:

  • 首先,我们增加了一个叫做orderProp<select>标签,这样我们的用户就可以选择我们提供的两种排序方法。

正如我们在步骤3中讨论数据绑定和迭代器的时候所说的一样,无论什么时候数据模型发生了改变(比如用户在下拉菜单中选了不同的顺序),AngularJS的数据绑定会让视图自动更新。没有任何笨拙的DOM操作!

app/js/controllers.js:

  • 我们修改了phones模型—— 手机的数组 ——为每一个手机记录其增加了一个属性。我们会根据age属性来对手机进行排序。
  • 我们在控制器代码里加了一行让orderProp的默认值为age。如果我们不设置默认值,这个模型会在我们的用户在下拉菜单选择一个顺序之前一直处于未初始化状态。

    现在我们该好好谈谈双向数据绑定了。注意到当应用在浏览器中加载时,“Newest”在下拉菜单中被选中。这是因为我们在控制器中把orderProp设置成了‘age’。所以绑定在从我们模型到用户界面的方向上起作用——即数据从模型到视图的绑定。现在当你在下拉菜单中选择“Alphabetically”,数据模型会被同时更新,并且手机列表数组会被重新排序。这个时候数据绑定从另一个方向产生了作用——即数据从视图到模型的绑定。

我们所做的更改可以通过一个单元测试或者一个端到端测试来验证正确性。我们首先来看看单元测试:

test/unit/controllersSpec.js:

  1. describe('PhoneCat controllers', function() {
  2. describe('PhoneListCtrl', function(){
  3. var scope, ctrl;
  4. beforeEach(function() {
  5. scope = {},
  6. ctrl = new PhoneListCtrl(scope);
  7. });
  8. it('should create "phones" model with 3 phones', function() {
  9. expect(scope.phones.length).toBe(3);
  10. });
  11. it('should set the default value of orderProp model', function() {
  12. expect(scope.orderProp).toBe('age');
  13. });

我们使用Jasmine的接口把PhoneListCtrl控制器提取到一个beforeEach块中,这个块会被所有的父块describe中的所有测试所共享。

运行这些单元测试,跟以前一样,执行./scripts/test.sh脚本,你应该会看到如下输出(注意:要在浏览器打开http://localhost:9876并进入严格模式,测试才会运行!):

现在我们把注意力转移到端到端测试上来。

test/e2e/scenarios.js:

  1. ...
  2. it('should be possible to control phone order via the drop down select box',
  3. function() {
  4. //let's narrow the dataset to make the test assertions shorter
  5. input('query').enter('tablet');
  6. expect(repeater('.phones li', 'Phone List').column('phone.name')).
  7. toEqual(["Motorola XOOM\u2122 with Wi-Fi",
  8. "MOTOROLA XOOM\u2122"]);
  9. select('orderProp').option('Alphabetical');
  10. expect(repeater('.phones li', 'Phone List').column('phone.name')).
  11. toEqual(["MOTOROLA XOOM\u2122",
  12. "Motorola XOOM\u2122 with Wi-Fi"]);
  13. });
  14. ...

端到端测试验证了选项框的排序机制是正确的。

你现在可以刷新你的浏览器,然后重新跑一遍端到端测试,或者你可以在上运行一下。

  • PhoneListCtrl控制器中,把设置那条语句删掉,你会看到AngularJS会在下拉菜单中临时添加一个空白的选项,并且排序顺序是默认排序(即未排序)。

总结