在这一步中,我们链接了filter过滤器与orderBy过滤。动态排序由创建的一个新模型属性实现,和重复器一起写,让数据绑定魔法来实现目标。
对搜索框的增加中,应用允许用户控制哪些手机用什么顺序显示在下拉列表中。
工作空间重置介绍 重置你的工作区间到第四步
git checkout -f step-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">
<span>{{phone.name}}</span>
<p>{{phone.snippet}}</p>
</li>
</ul>
我们对 index.html
模板修改了如下:
首先,我们增加了一个
<select>
html元素叫orderProp,这样我们的用户能选择两种不同的排序选项。
我们链接了filter过滤器与orderBy过滤器,去进一步处理输入到重复器中,orderBy是一个这样的过滤器,他拿到一个输入数组,复制他,将拷贝重新排序,然后返回拷贝。
Angular在选择元素与 orderProp
之间创建了双向数据绑定,然后 orderProp
用作 orderBy
过滤器的输入。 像我们在第三步中讨论的关于数据绑定与重复器一样,无论模型怎么修改,Angular的数据绑定能让视图自动地更新,不需要臃肿的DOM操作代码。
控制器
app/js/controllers.js:
var phonecatApp = angular.module('phonecatApp', []);
phonecatApp.controller('PhoneListCtrl', function ($scope) {
$scope.phones = [
{'name': 'Nexus S',
'snippet': 'Fast just got faster with Nexus S.',
'age': 1},
{'name': 'Motorola XOOM™ with Wi-Fi',
'snippet': 'The Next, Next Generation tablet.',
'age': 2},
{'name': 'MOTOROLA XOOM™',
'snippet': 'The Next, Next Generation tablet.',
'age': 3}
];
$scope.orderProp = 'age';
});
我们修改了phones模型——手机数组——并增加了一个age属性给每一条记录,这条属性是用来让手机按年龄排序。
我们给控制器增加了一行,设置默认值orderProp给age,如果我们没有设置默认值,order by 过滤器将不会初始化,直到我们下拉菜单,选中一个选项。这是一个好时间去讨论双向数据绑定,注意app被浏览器加载之后,最新是被下载菜单选中,这是因为在控制器中我们设定orderProp给
age
,所以我们绑定工作是从我们的模型到UI,现在如果你在下拉菜单中选择了Alphabetically,模型会很好的更新,手机列表会重新排序,那就是数据绑定做了在反向方向做了他的工作,从UI到模型。
测试
这些修改必须通过我们的单元测试和端对端测试,首先让我们看单元测试 test/unit/controllersSpec.js:
describe('PhoneCat controllers', function() {
describe('PhoneListCtrl', function(){
var scope, ctrl;
beforeEach(module('phonecatApp'));
beforeEach(inject(function($controller) {
scope = {};
ctrl = $controller('PhoneListCtrl', {$scope: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的API去提取控制器构造器到beforeEach模块,在describe父模块中所有测试共享。 你可能在Karma选卡中看到下面的输出:
Chrome 22.0: Executed 2 of 2 SUCCESS (0.021 secs / 0.001 secs)
让我们把注意力移到端对端测试: test/e2e/scenarios.js:
...
it('should be possible to control phone order via the drop down select box', function() {
var phoneNameColumn = element.all(by.repeater('phone in phones').column('phone.name'));
var query = element(by.model('query'));
function getNames() {
return phoneNameColumn.map(function(elm) {
return elm.getText();
});
}
query.sendKeys('tablet'); //let's narrow the dataset to make the test assertions shorter
expect(getNames()).toEqual([
"Motorola XOOM\u2122 with Wi-Fi",
"MOTOROLA XOOM\u2122"
]);
element(by.model('orderProp')).element(by.css('option[value="name"]')).click();
expect(getNames()).toEqual([
"MOTOROLA XOOM\u2122",
"Motorola XOOM\u2122 with Wi-Fi"
]);
});...
端对端测试验证了选择横下中的排序机制工作正常。 你可以重复运行 npm run protractor 去看测试运行。
实验
在PhoneListCtrl控制器中,移走设定orderProp值的语句,你会看到Angular暂时给下拉列表增加空白(“unknown”)选项,然后排列是无序或者自然顺序。 增加{{orderProp}}绑定到index.html模板,用文本显示当前的值。 在排序前面用一个 - 反转排列 :<option value="-age">Oldest</option>
总结
现在你已经在应用中增加了一个排序,并测试通过了。去 第5步,学习关于Angular服务,Angular怎么使用依赖注入。