在这一步你会增加一个让用户控制手机列表显示顺序的特性。动态排序可以这样实现,添加一个新的模型属性,把它和迭代器集成起来,然后让数据绑定完成剩下的事情。

请重置工作目录:

git checkout -f step-4

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

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

模板

app/index.html

Search: <input ng-model="query">
Sort by:
<select ng-model="orderProp">
<option value="name">Alphabetical</option>
<option value="age">Newest</option>
</select> <ul class="phones">
<li ng-repeat="phone in phones | filter:query | orderBy:orderProp">
{{phone.name}}
<p>{{phone.snippet}}</p>
</li>
</ul>

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

  • 首先,我们增加了一个叫做orderProp<select>标签,这样我们的用户就可以选择我们提供的两种排序方法。
  • 然后,在filter过滤器后面添加一个orderBy过滤器用其来处理进入迭代器的数据。orderBy过滤器以一个数组作为输入,复制一份副本,然后把副本重排序再输出到迭代器。

AngularJS在select元素和orderProp模型之间创建了一个双向绑定。而后,orderProp会被用作orderBy过滤器的输入。

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

控制器

app/js/controllers.js:

function PhoneListCtrl($scope) {
$scope.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}
]; $scope.orderProp = 'age';
}
  • 我们修改了phones模型—— 手机的数组 ——为每一个手机记录其增加了一个age属性。我们会根据age属性来对手机进行排序。
  • 我们在控制器代码里加了一行让orderProp的默认值为age。如果我们不设置默认值,这个模型会在我们的用户在下拉菜单选择一个顺序之前一直处于未初始化状态。

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

测试

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

test/unit/controllersSpec.js:

describe('PhoneCat controllers', function() {

  describe('PhoneListCtrl', function(){
var scope, ctrl; beforeEach(function() {
scope = {},
ctrl = new PhoneListCtrl(scope);
}); it('should create "phones" model with 3 phones', function() {
expect(scope.phones.length).toBe(3);
}); it('should set the default value of orderProp model', function() {
expect(scope.orderProp).toBe('age');
});
});
});

单元测试现在验证了默认值被正确设置。

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

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

Chrome: Runner reset.
..
Total 2 tests (Passed: 2; Fails: 0; Errors: 0) (3.00 ms)
Chrome 19.0.1084.36 Mac OS: Run 2 tests (Passed: 2; Fails: 0; Errors 0) (3.00 ms)

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

test/e2e/scenarios.js:

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

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

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

练习

  • PhoneListCtrl控制器中,把设置orderProp那条语句删掉,你会看到AngularJS会在下拉菜单中临时添加一个空白的选项,并且排序顺序是默认排序(即未排序)。
  • index.html模板里面添加一个`{{orderProp}}绑定来实时显示它的值。

总结

现在你已经为你的应用提供了搜索功能,并且完整的进行了测试。步骤5我们将学习AngularJS的服务以及AngularJS如何使用依赖注入。

[转载]AngularJS入门教程04:双向绑定的更多相关文章

  1. [转载]AngularJS入门教程00:引导程序

    我们现在开始准备编写AngularJS应用——phonecat.这一步骤(步骤0),您将会熟悉重要的源代码文件,学习启动包含AngularJS种子项目的开发环境,并在浏览器端运行应用. 进入angul ...

  2. Angular系列----AngularJS入门教程04:迭代器过滤(转载)

    我们在上一步做了很多基础性的训练,所以现在我们可以来做一些简单的事情喽.我们要加入全文检索功能(没错,这个真的非常简单!).同时,我们也会写一个端到端测试,因为一个好的端到端测试可以帮上很大忙.它监视 ...

  3. [转载]AngularJS入门教程02:AngularJS模板

    是时候给这些网页来点动态特性了——用AngularJS!我们这里为后面要加入的控制器添加了一个测试. 一个应用的代码架构有很多种.对于AngularJS应用,我们鼓励使用模型-视图-控制器(MVC)模 ...

  4. [转载]AngularJS入门教程03:迭代器

    我们在上一步做了很多基础性的训练,所以现在我们可以来做一些简单的事情喽.我们要加入全文检索功能(没错,这个真的非常简单!).同时,我们也会写一个端到端测试,因为一个好的端到端测试可以帮上很大忙.它监视 ...

  5. [转载]AngularJS入门教程01:静态模板

    为了说明angularJS如何增强了标准HTML,我们先将创建一个静态HTML页面模板,然后把这个静态HTML页面模板转换成能动态显示的AngularJS模板. 在本步骤中,我们往HTML页面中添加两 ...

  6. 【转载】图灵AngularJS入门教程

    摘自图灵的AngularJS入门教程:http://www.ituring.com.cn/article/13471 感觉非常不错,所以推荐到首页一下! (一)Hello World! 开始学习Ang ...

  7. AngularJS入门教程:日期格式化

    AngularJS入门教程:日期格式化[转载] 本地化日期格式化: ({{ today | date:'medium' }})Nov 24, 2015 2:19:24 PM ({{ today | d ...

  8. Angular系列----AngularJS入门教程05:双向绑定(转载)

    在这一步你会增加一个让用户控制手机列表显示顺序的特性.动态排序可以这样实现,添加一个新的模型属性,把它和迭代器集成起来,然后让数据绑定完成剩下的事情. 请重置工作目录: git checkout -f ...

  9. Angular系列----AngularJS入门教程00:引导程序(转载)

    我们现在开始准备编写AngularJS应用——phonecat.这一步骤(步骤0),您将会熟悉重要的源代码文件,学习启动包含AngularJS种子项目的开发环境,并在浏览器端运行应用. 进入angul ...

随机推荐

  1. 与"shark"相关的表达

    The word shark can be used to describe someone who is tricky and uses other people. Shark这个单词可以用来形容一 ...

  2. Flask-SQLAlchemy 配置,处理对象-关系,一对多,多对多

      ORM(Object Relational Mapper) 对象关系映射.指将面对对象得方法映射到数据库中的关系对象中. Flask-SQLAlchemy是一个Flask扩展,能够支持多种数据库后 ...

  3. SQL——模糊查询

    前言 在这个大数据时代,我们都离不开对数据的增删改查,增加.删除.修改这些看似都是一步完成的事情,但是对于查询来说,好的查询SQL可以大大的减少系统内存运行时间,提高系统的反应速度.这里简单的介绍一下 ...

  4. 解读人:闫克强,Metabolic and gut microbial characterization of obesity-prone mice under high-fat diet(高脂饮食下易胖倾向小鼠的代谢和肠道微生物菌群特征分析)

    单位: 上海中医药大学 蚌埠医学院 上海交通大学附属第六人民医院 夏威夷大学癌症中心 第二军医大学 技术:非靶向代谢组学,16S rRNA测序技术 一. 概述: 本研究对小鼠进行高脂饮食,根据体重增长 ...

  5. LCA 【bzoj1787】[Ahoi2008]Meet 紧急集合

    LCA [bzoj1787][Ahoi2008]Meet 紧急集合 题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1787 注意到边权为一 ...

  6. CF986A Fair

    题目描述 Some company is going to hold a fair in Byteland. There are n n n towns in Byteland and m m m t ...

  7. js unicode

    参考 http://www.ruanyifeng.com/blog/2014/12/unicode.html

  8. Python Unittest - Test Fixtures 测试夹具

    一.什么是测试夹具 定义单个或者多个测试所需的环境准备(setUp),以及环境清理(tearDown). 例:连接数据库,或者创建Selenium WebDriver driver实例 二.测试夹具有 ...

  9. jquery——解决鼠标移入移出导致盒子不停移动的bug

    使用mouseover().mouseout()时会出现这样一种情况,鼠标快速多次移入移出后这个盒子会在鼠标不动后继续运动 代码如下: <!DOCTYPE html> <html l ...

  10. LeetCode 128 Longest Consecutive Sequence 一个无序整数数组中找到最长连续序列

    Given an unsorted array of integers, find the length of the longest consecutive elements sequence.Fo ...