Bootstrap6.1:SportStore:1个实打实的应用

事先的小例子让我们演示了AngularJS的一部分风味,但他俩紧缺上下文。要缓解这些难题,作者要创立1个不难单真实的电子商务应用。

小编将开创一个在线产品分类,客户可以由此分类和页面浏览,二个购物车用户拉长或移除产品,当客户在结账时,进入他们的购物明细,列出他们的订单。小编也会成立3个管制区域,包涵CRUD,管理分类,并且爱护它,唯有已经报到的社团者才能修改它。

作者本章的目的,通过创立1个更真实的事例,是让您倍感到,三个实事求是的AngularJS开发。小编想关切于AngularJS,当然,也要简明地与外部系统合二为一,如数据存储,会全盘忽略任何的,如开发处理。

唤醒:单元测试

AngularJS对单元测试提供许多卓越的协助,但我不大概在本书的末梢一章才说它。因为你真正要求了然AngularJS怎么样行事,才能写出综合的单元测试。

作者在第一5章才讲单元测试,可是她提出我们按梯次读,那样才能通晓单元测试的表征,是怎么样塑造的。

  1. 开始

此间要设置一些可选的AngularJS性情,来安装服务器,让她分发数据。

  1. 预备数据

先是步是创建一个新的Deployd应用。你要创立一个路子,来放生成的文书。我称它路径叫deployd,放在angularjs文件夹同级别。

留意:我在率先章让你下载Deployd,若是您没那么做,快去下载吧。

在命令行中,进入新路线,输入上边代码

dpd create sportsstore

要从头新服务器,输入上边的命令

dpd –p 5500 sportsstore\app.dpd

dashboard 

唤醒:那是windows风格的文书分隔符。你在其他平台上大概是sportsstore/app.dpd。

在Deployd dashboard,用于配克服务器,突显在浏览器中。

  1. 创办数据结构

下一步是便捷Deployd,要存储的数量的布局。在dashboard上点击粉青的大按钮,从pop-up菜单中,选拔Collection。设置集合的名字为
“/products”(没有双引号)。

Deployd会指示您穿件JSON对象的属性,属性如下:

Name

Type

Required

name

String

Yes

description

String

Yes

category

String

Yes

price

Number

Yes

当你完了了质量添加,dashboard会匹配,确保您输入的属性名字不错,并选取了合情合理的门类。

指示:注意Deployd已经添加id属性。他会用于独一无二地标识数据库中的对象。Deployd会自动指派独一无二的值给id属性。在第⑩章,当作者完结管理员功用时,会依据这个值。

  1. 添加数码

今昔,我曾经定义了目的的构造。我可以加上产品的密切。点击Data
link,在左侧。他会显示grid编辑器,让您填入属性的值。

决不顾虑指派id属性的值,因为Deployd会自动生成他们。

提示:Deployd的number字段的浮点显示。

  1. 测试数据服务

要测试Deployd已经不错配置并工作,打开浏览器窗体,导航到上边的UENCOREL:

http://localhost:5500/products

一经你早就在当地电脑安装Deployd,并不曾改动它的端口号。/products
U本田UR-VL是询问/products集合中的内容,作为三个JSON字符串标示。注意,id字段差距。

  1. 准备使用

在作者开首写应用前,小编需求准备angularjs文件夹,来创建路径结构,放置AngularJS和Bootstrap文件。

1.2.① 、成立路径结构

在angularjs文件夹下,创造如下目录:

Name

Description

components

包含自包含的客制化AngularJS组件

controllers

包含应用的控制器,作者会在第13章讲。

filters

包含自定义filters。作者在第14章深度介绍filters

ngmodules

包含可选的AngularJS模块。

views

包含SportsStore应用的局部视图。Views包含指令和filters的组合。作者在第10-17章讲。

 

1.2.2、安装AngularJS和BootStrap文件

作者的习惯,将AngularJS JavaScript文件和Bootstrap
CSS文件一向放到angularjs路径,将AngularJS可选模块放在ngmodules路径。

Angularjs文件夹下有:angular.js,bootstrap.css,bootstrap-theme.css

Ngmodules文件夹下有:angular-route.js,angular-resource.js

 

1.2.③ 、打造基本的文稿

小编喜欢先用静态数据模拟各样部分的内容,早先八个新的AngularJS应用。SportsStroe应用的中坚布局,是经典的两列布局。第贰列是分类,用户过滤第贰列要显示的产品组。

首先步是要创立贰个顶尖HTML文件。在angularjs文件夹下,新建app.html文件。

<!DOCTYPE html>

<html ng-app="sportsStore">

<head>

<title>SportsStore</title>

<script src="angular.js"></script>

<link href="bootstrap.css" rel="stylesheet" />

<link href="bootstrap-theme.css" rel="stylesheet" />

<script>

angular.module("sportsStore", []);

</script>

</head>

<body>

<div class="navbar navbar-inverse">

<a class="navbar-brand" href="#">SPORTS STORE</a>

</div>

<div class="panel panel-default row">

<div class="col-xs-3">

Categories go here

</div>

<div class="col-xs-8">

Products go here

</div>

</div>

</body>

</html>

该文件包蕴三个AngularJS钦赐,第②个是调用angular.module方法。

<script>

angular.module("sportsStore", []);

</script> 

模块是AngularJS应用的头等构建块,该方法调用穿件八个新的模块,叫做sportsStroe。

其次个地点,是html成分上的ng-app指令:

<html ng-app="sportsStore"> 

Ng-app指令使得sportsStore模块中定义的效劳,在HTML范围内可用。小编喜欢将ng-app指令应用到html成分上,你也得以置身body元素上。

提示:用http://localhost:5000/app.html
。来做客该页面。而不是Deployd服务器的5500端口。

  1. 显示模拟产品数量

小编先定义本地模拟初阶化数据,第拾章会用从Deployd服务器取得的数额替换该数量。

2.① 、创制控制器

首先要加二个控制器。该控制器创造后,会为全部应用服务,作者成为顶尖控制器。然后,小编会将几个有关的控制器,放到1个文书中,但把超级控制器放在app.html文件中。

指示:小编保持拔尖控制器和其余文件分割的原由,是它在版本控制系统发生变更时,要一眼就能见到它。当主功用逐渐形成,拔尖控制器会发生逐渐发生变化,那是潜在地打破,大概在富有的应用中。那一点在开发周期中,作者想要知道顶尖控制器前边的有的事物,可以确保改变经过了丰盛的测试。

在controllers/sportsStore.js :

angular.module("sportsStore")

.controller("sportsStoreCtrl", function ($scope) {

$scope.data = {

products: [

{ name: "Product #1", description: "A product",

category: "Category #1", price: 100 },

{ name: "Product #2", description: "A product",

category: "Category #1", price: 110 },

{ name: "Product #3", description: "A product",

category: "Category #2", price: 210 },

{ name: "Product #4", description: "A product",

category: "Category #3", price: 202 }]

};

});

注意第3行调用angular.module方法,那在app.html也有雷同的措施调用。不一样之处是,在app.html中定义的module,我提供了二个额外的参数,像那样:

angular.module("sportsStore", []);

其次个参数是三个数组,它将来是空的,它是sportsStore模块基于的模块列表,它高速AngularJS,定位并提供这个模块中富含的法力。小编稍后会添法郎素到那个数组中。可是今后,紧要的是,要领会,当你提供二个数组——空或不空,它都高速AngularJS,要开创多少个新的模块。当你品味创造1个模块,然而它曾经存在时,AngularJS会报告几个荒唐,所以您需求确保您的模块名字的唯一性。

作为相比,在sportsStroe.js文件中调用angular.module方法,不分包首个参数:

angular.module("sportsStore")

马虎第二个参数,会报告AngularJS,你要稳定2个早已定义过的模块,在那种情状下,如若钦命的模块不存在,AngularJS会报告二个颠倒是非,
所以你要力保模块已经被创立。

采取angular.module方法再次回到的Module对象,都能被用于定义应用效益。笔者曾经使用controller方法,定义了两个控制器。

专注:小编不常像这么在HTML文件中,成立主应用模块,因为她可以被归纳地停放到Javascript文件中。作者将宣示分成若干小一些的原因,是几度使用angular.module方法,导致无终止的混杂,笔者想让您放在心上到它。

SportsStore应用中,一流控制器的最紧要脚色,是概念用于在分裂视图上显得的数额。在第一3章,会师到多个控制器级联排列。

只顾:当笔者定义控制器的限定上的数量时,将数据对象的数组,定义在data上,它会叠加到scope。你不只怕不在定义数据时相当小心,因为只要您在scope上直接指派属性(如$scope.products=[data]),因其他控制器可以读取,但一而再不可以改改数据。小编将在第贰3章详细表明。

2.② 、突显产品明细

要展现产品明细,要求给app.html文件添加一些HTML。AngularJS让突显数据变得简单。

<!DOCTYPE html>

<html ng-app="sportsStore">

<head>

<title>SportsStore</title>

<script src="angular.js"></script>

<link href="bootstrap.css" rel="stylesheet" />

<link href="bootstrap-theme.css" rel="stylesheet" />

<script>

angular.module("sportsStore", []);

</script>

<script src="controllers/sportsStore.js"></script>

</head>

<body ng-controller="sportsStoreCtrl">

<div class="navbar navbar-inverse">

<a class="navbar-brand" href="#">SPORTS STORE</a>

</div>

<div class="panel panel-default row">

<div class="col-xs-3">

Categories go here

</div>

<div class="col-xs-8">

<div class="well" ng-repeat="item in data.products">

<h3>

<strong>{{item.name}}</strong>

<span class="pull-right label label-primary">

{{item.price | currency}}

</span>

</h3>

<span class="lead">{{item.description}}</span>

</div>

</div>

</div>

</body>

</html>

那边有七个转变。第多个,添加了三个script成分,导入sportsStore.js文件。该文件包罗sportsStoreCtrl控制器。因为作者曾经在app.html文件中定义了sportsStore模块,然后在sportsStore.js文件中一定并采用它,我须求保障sportsStore模块的定义script,出现在引用此前。

第二个改变,是用ng-controller指令,将控制器选拔到视图,像那样:

<body ng-controller="sportsStoreCtrl">

作者会利用sportsStoreCtrl控制器,为总体应用提供支撑,所以,他把它利用到body成分上。

2.2.一 、生成内容成分

最后三个变更,是创办了出品明细元素。AngularJS提供的3个最可行的通令,是ng-repeat,它为数量数组中的各种对象生成元素。

<div class="well" ng-repeat="item in data.products">

然后我在多少绑定表明式中,引用当前目的。

<div class="well" ng-repeat="item in data.products">

<h3>

<strong>{{item.name}}</strong>

<span class="pull-right label label-primary">{{item.price | currency}}</span>

</h3>

<span class="lead">{{item.description}}</span>

</div>

Name和description值被直接插入HTML成分,但price属性不是这般:小编利用了一个filter。多少个filter格式或order,是要在view中显得的数据值。AngularJS有局地内建的filters,包括currency
filter,它用币种金额,格式化数字。Filters使用 | 符号应用。Item.price |
currency,会告知 AngularJS,使用currency
filter,传递item对象的price属性的值。

Currency
filter私行认同使用USD格式,但小编会在第贰4章表达,怎么选拔AngularJS本地化filters,来突显其余币种格式。小编也会在第二4章,说明内建filters,并给你出示怎么创制和谐的。

  1. 突显分类列表

下一步是显得分类列表,让用户能够过滤突显的产品组。完成该本性,要求扭转客户用于导航的要素,采纳2个出品分类后,更新明细面板,只显示被选中分类的出品。

3.一 、制造分类列表

我想从成品数据对象动态变化分类成分,而不是硬编码HTML成分。动态途径设置起来更复杂一点,但它会同意SportsStore应用能半自动感应产品分类的成形。那象征笔者不得不从产品数据对象中生成一个满世界无双的分类名称的列表。该天性AngularJS不带有,但经过创办和行使二个自定义过滤器,可以不难地落实。在filters路径下,创造多个customFilters.js:

angular.module("customFilters", [])

.filter("unique", function () {

return function (data, propertyName) {

if (angular.isArray(data) && angular.isString(propertyName)) {

var results = [];

var keys = {};

for (var i = 0; i < data.length; i++) {

var val = data[i][propertyName];

if (angular.isUndefined(keys[val])) {

keys[val] = true;

results.push(val);

}

}

return results;

} else {

return data;

}

}

});

自定义过滤器,使用Module对象的filter方法定义,它经过angular.module方法得到并创办。小编接纳新建1个模块,叫做customFilters,来含有他的过滤器,主要可以突显如何定义并在应用中结成两个模块。

提醒:当您给现存模块添加组件或创办壹个新模块时,没有先后顺序。小编希望她定义的功能在事后的两样拔取里重用时,他援救于成立模块。自定义过滤器倾向于可拔取,因为数量格式是任何AngularJS应用都急需的,也是开发者要求的公家格式。

Filter方法的参数,是filter的名字,例子中是unique,它回到一个factory
function,该函数并不实际工作,而是再次回到一个filter
function。当AngularJS必要创设三个filter的实例时,它调用factory
function,filter function就会被调用,以履行过滤。

有着的filter
function都有3个参数,传递他们必要的格式的数额,但我的filter定义了3个格外的参数,叫做propertyName,它能用于内定要从要生成哪个字段的绝无仅有列表。过滤效果的兑现很不难:枚举数据对象的故事情节,用propertyName参数,创设一个无比的值的列表。

提醒:笔者没有没有将过滤器功效硬编码为寻找category属性,那会限制unique过滤器在任何应用的选定。

过滤效果重返过滤后的多少。小编运用anagular.isArray和angular.isString,检查传入的多寡是不是是数组,属性名是不是是字符串。然后,他用angular.isUndefined方法,检查该属性是或不是定义。AngularJS提供一组有用的工具方法,包蕴允许你检核查象和品质类型。小编会在第⑤章完整地讲述。若是过滤器接收到2个数组和一个属性名,然后他转移并重返二个无比的属性值的数组。不然,他回到将吸纳到的数量原封不动地回到。

晋升:让过滤器仅展现用户须求的始末,而不是在scope中修改原始数据。

3.2、生成分类导航链接

下一步,生成用户可以点击的出品分类的领航链接。这须求利用上节创办的unique过滤器。

<!DOCTYPE html>

<html ng-app="sportsStore">

<head>

<title>SportsStore</title>

<script src="angular.js"></script>

<link href="bootstrap.css" rel="stylesheet" />

<link href="bootstrap-theme.css" rel="stylesheet" />

<script>

angular.module("sportsStore", ["customFilters"]);

</script>

<script src="controllers/sportsStore.js"></script>

<script src="filters/customFilters.js"></script>

</head>

<body ng-controller="sportsStoreCtrl">

<div class="navbar navbar-inverse">

<a class="navbar-brand" href="#">SPORTS STORE</a>

</div>

<div class="panel panel-default row">

<div class="col-xs-3">

<a ng-click="selectCategory()"

class="btn btn-block btn-default btn-lg">Home</a>

<a ng-repeat="item in data.products | orderBy:’category’ | unique:’category’"

ng-click="selectCategory(item)" class=" btn btn-block btn-default btn-lg">

{{item}}

</a>

</div>

<div class="col-xs-8">

<div class="well" ng-repeat="item in data.products">

<h3>

<strong>{{item.name}}</strong>

<span class="pull-right label label-primary">

{{item.price | currency}}

</span>

</h3>

<span class="lead">{{item.description}}</span>

</div>

</div>

</div>

</body>

</html>

在sportsStore模块中,定义一个对customFilters的依靠。

angular.module("sportsStore", ["customFilters"]);

那就是declaring a
dependency。在本例中,作者申明sportsStore模块倚重于customFilters模块的成效。那会导致AngularJS定位customFilters模块,并保障它可用,然后可以引用它包蕴的组件,如过滤器和控制器。该进程叫做resolving
the dependency。

指示:申明和治本模块和此外类型组件的长河,叫做dependency
injection,是AngularJS的着力,小编会在第柒章解释该过程。

3.2.一 、生成导航成分

最有趣的的局地,是拔取ng-repeat成分,为每一个产品分类生成贰个成分。

<a ng-click="selectCategory()" class="btn btn-block btn-default btn-lg">Home</a>

<a ng-repeat="item in data.products | orderBy:’category’ | unique:’category’"

ng-click="selectCategory(item)" class=" btn btn-block btn-default btn-lg">

{{item}}

</a>

Ng-repeat属性值的首先有些,和变化产品明细的同样,item in
data.products,它报告ng-repeat指令要枚举data.products数组的靶子,指派当前目标给叫做item的变量,并复制利用该指令的a成分。

属性值的第叁片段,告诉AngularJS,传递data.products数组给叫做orderBy的内建过滤器,用于排序数组。该orderBy过滤器,有贰个参数,内定用于排序的性子。小编会在第二4章完整地叙述orderBy过滤器。

指示:注意小编在单引号之间,钦命了属性名。默许地,AngularJS借使表达式中的名字,指向scope中定义的变量。要指定1个静态值,不得不动用字符串,在Javascript中,须求单引号或双引号。

过滤器有一个很棒的性状,通过 |
将她们链式调用。AngularJS依据过滤器排列的逐一,应用他们。那意味,category属性在排序过后,才传递给unique过滤器。你看看我怎么样钦赐unique过滤器要操作的性格:

<a ng-repeat="item in data.products | orderBy:’category’ | unique:’category’"

那般的结果是,data.products数组传递给orderBy过滤器,它依据category属性排序。Ta排序过的数组传递给unique,它回到二个字符串数组,包蕴独一无二的category值———因为unique过滤处理进程中不改变值的依次,结果保持上个过滤器的排序。

升迁:小编可以颠倒使用过滤器的逐条,结果同样。不一样的是,orderBy过滤器会效率于1个字符串数组,而不是product对象。orderBy过滤器设计用来操作对象的,但你可以因此采取orderBy:’toString()’,来排序字符串。不要忘了引号,不然,AngularJS找三个名为toString的scope属性,而不是调用toString方法。

3.2.二 、处理点击事件

小编在a成分上采纳ng-click指令,可以对应用户的点击。AngularJS提供一组内建命令,小编将在第贰1章介绍,它们恩可以在相应事件时,不难地调用控制器行为。ng-click指令的名字,提出指明AngularJS在点击事件触发时,要做什么样。

<a ng-click="selectCategory()"class="btn btn-block btn-default btn-lg">Home</a>

<a ng-repeat="item in data.products | orderBy:’category’ | unique:’category’"

ng-click="selectCategory(item)"class=" btn btn-block btn-default btn-lg">

{{item}}

</a>

在app.html中有四个a成分。第③个是静态地,创制Home按钮,小编用户浮现全数成品的具有分类。在该因素中,小编设置ng-click指令,它调用一个控制器行为,叫做selectCategory,没有参数。前边小编会成立该作为,未来,紧要的事务是时刻思念另一个a成分,它的selectCategory行为有多个item变量值作为参数。点击时,例如selectCategory(‘Category
#1’)。

3.叁 、选拔分类    

在浏览器中点击分类按钮,不会有任何功效,因为ng-click指令设置为调用多个还尚未定义的行事。当您品尝访问二个不设有的一言一动或数量时,AngularJS不会埋怨。那给debugging带来了小麻烦,因为呈现错误结果,但也更灵敏。作者将在第贰3章描述如何在更深的地方使用控制器和它的限制。

3.3.壹 、定义控制器

我要定义叫做selectCategory的一颦一笑,来响应用户对分类按钮的点击。他不像将作为添加到一流sportsStoreCtrl控制器上,那是整整应用提供行为和数量的地点。取而代之,我新建三个控制器,专用于产品列表和归类视图。controllers/productListControllers.js。

唤醒:你只怕会问作者,为何作者的控制器的名字,比过滤器的更标准。原因是,过滤器更通用,准备在其余应用中采纳。

angular.module("sportsStore")

.controller("productListCtrl", function ($scope, $filter) {

var selectedCategory = null;

$scope.selectCategory = function (newCategory) {

selectedCategory = newCategory;

}

$scope.categoryFilterFn = function (product) {

return selectedCategory == null ||

product.category == selectedCategory;

}

});

笔者调用app.html文件中定义的sportsStroe模块的controller方法(记住,2个参数的angular.module方法,以为那找现有模块,而多个参数的情致,是创办一个新模块)。

该控制器叫做productListCtrl,它定义3个誉为selectCategory的行为。该控制器还定义了2个名叫categoryFilterFn的行事,它以三个成品对象作为参数,它在未曾分类被选中,或有3个分类被入选并且该产品输入它时,重回true。

提醒:注意selectedCategory变量没有概念在scope上,它只是一个平常化的JavaScript变量,意味着它不只怕从指令访问或view的数据绑定中。这样做的结果是,创制了selectCategory行为,用于安装分类,categoryFilterFn用于过滤产品对象,但被入选的归类的底细,保持私有。笔者在SportStore应用中,不借助此本性。

3.3.贰 、应用控制器和过滤产品

作者不得不采纳ng-contorller指令,应用控制器到视图,让ng-click指令可以调用selectCategory行为。不然,包罗ng-click指令的因素的回来,会是一级sportsStoreCtrl控制器,它不带有该表现。

<!DOCTYPE html>

<html ng-app="sportsStore">

<head>

<title>SportsStore</title>

<script src="angular.js"></script>

<link href="bootstrap.css" rel="stylesheet" />

<link href="bootstrap-theme.css" rel="stylesheet" />

<script>

angular.module("sportsStore", ["customFilters"]);

</script>

<script src="controllers/sportsStore.js"></script>

<script src="filters/customFilters.js"></script>

<script src="controllers/productListControllers.js"></script>

</head>

<body ng-controller="sportsStoreCtrl">

<div class="navbar navbar-inverse">

<a class="navbar-brand" href="#">SPORTS STORE</a>

</div>

<div class="panel panel-default row" ng-controller="productListCtrl">

<div class="col-xs-3">

<a ng-click="selectCategory()"

class="btn btn-block btn-default btn-lg">Home</a>

<a ng-repeat="item in data.products | orderBy:’category’ | unique:’category’"

ng-click="selectCategory(item)" class=" btn btn-block btn-default btn-lg">

{{item}}

</a>

</div>

<div class="col-xs-8">

<div class="well"

ng-repeat="item in data.products | filter:categoryFilterFn">

<h3>

<strong>{{item.name}}</strong>

<span class="pull-right label label-primary">

{{item.price | currency}}

</span>

</h3>

<span class="lead">{{item.description}}</span>

</div>

</div>

</div>

</body>

</html>

作者添加script成分,导入productListControllers.js文件,在含蓄分类列表和制品列表的视图部分,使用ng-controller指令来使用productListCtrl控制器。

将productListCtrl控制器放在sportsStorectrl控制器范围内,意味着小编可以采纳先进的controller
scope
inheritance,作者将在第①3章解释。productListCtrl继承sportsStoreCtrl中定义的data.products数组和别的别的数据和作为。那样做的补益,是可以限制控制器作用在采用上的限制,更易于执行单元测试,放置组件间非预期的重视。

另贰个改动,是在风谲云诡产品明细的ng-repeat上计划:

<div class="well" ng-repeat="item in data.products | filter:categoryFilterFn">

AngularJS提供的3个内建的过滤器,叫做filter。它处理2个集结,采用她饱含的靶子的子集。我将在第②4章描述该技能。通过在ng-repeat指令上行使它,确保唯有当前被入选的分类的成品显示。

3.④ 、高亮被选中的分类

用户可以点击分类按钮,来过滤产品,但从不视觉反馈,哪个范磊被选中了。小编将为当选的分类应用btn-primary
CSS
class。第贰步,在控制器中添加一个行事,它接受三个分类。假若它是被选中的归类,再次来到CSS
class名。

提醒:注意我怎么在AngularJS模块上链式调用方法。那是因为Module定义的办法,同样重回Module,那点和fluent
API一样。

angular.module("sportsStore")

.constant("productListActiveClass", "btn-primary")

.controller("productListCtrl", function ($scope, $filter, productListActiveClass) {

var selectedCategory = null;

$scope.selectCategory = function (newCategory) {

selectedCategory = newCategory;

}

$scope.categoryFilterFn = function (product) {

return selectedCategory == null ||

product.category == selectedCategory;

}

$scope.getCategoryClass = function (category) {

return selectedCategory == category ? productListActiveClass : "";

}

});

小编不想在行为代码里钦赐class的名字,所以作者运用在Moduled对象上行使constant方法,定义二个称呼productListActiveClass的固定值。它同意本身改变class,每趟要利用时。要在控制器中做客该值,我不得不声明constant名字作为依靠,如上边那样。

.controller("productListCtrl", function ($scope, $filter, productListActiveClass) {

继之,可以在getCategoryClass行为中,使用productListActiveClass,它归纳地反省它接受到的归类,重返class
名字或空字符串。

getCategoryClass行为看起来有个别意外,但它能够在种种分类导航按钮中调用,传递分类的名字作为参数。要动用CSS
class,小编接纳ng-class指令。

<div class="col-xs-3">

<a ng-click="selectCategory()"

class="btn btn-block btn-default btn-lg">Home</a>

<a ng-repeat="item in data.products | orderBy:’category’ | unique:’category’"

ng-click="selectCategory(item)" class=" btn btn-block btn-default btn-lg"

ng-class="getCategoryClass(item)">

{{item}}

</a>

</div>

Ng-class属性,它会动用geCategoryClass重返的class 名。我将在第21章讲。

3.五 、添加分页

分页,一次突显一定数量的产品。须求三步才能兑现分页:修改控制器,scope跟踪分页状态,完结过滤器,更新视图。

3.5.① 、更新控制器

在productListControllers.js文件中,更新控制器,以跟踪分页。

angular.module("sportsStore")

.constant("productListActiveClass", "btn-primary")

.constant("productListPageCount", 3)

.controller("productListCtrl", function ($scope, $filter,

productListActiveClass, productListPageCount) {

var selectedCategory = null;

$scope.selectedPage = 1;

$scope.pageSize = productListPageCount;

 

$scope.selectCategory = function (newCategory) {

selectedCategory = newCategory;

$scope.selectedPage = 1;

}

$scope.selectPage = function (newPage) {

$scope.selectedPage = newPage;

}

$scope.categoryFilterFn = function (product) {

return selectedCategory == null ||

product.category == selectedCategory;

}

$scope.getCategoryClass = function (category) {

return selectedCategory == category ? productListActiveClass : "";

}

$scope.getPageClass = function (page) {

return $scope.selectedPage == page ? productListActiveClass : "";

}

});

每页产品的数码被定义为常量,叫做productListPageCount。在控制器里,俺在scope上定义变量,曝露常量值(所以小编能在view上访问它)和方今被挑选的页。作者曾经定义了作为,selectPage,允许被选拔的页,编程其他页。getPageClass,设计用来ng-class指令,来高亮被选中的页,和事先被入选的分类一样。

晋升:你大概会纳闷,为何视图无法平素访问常量值,而是要通过scope来方便地暴露。答案是,AngularJS努力放置组件间紧凑地耦合,小编在第2章描述过。如果视图可以平昔访问服务和常量值,那么她不难为止无停歇的耦合和凭借,难于测试和爱抚。

3.5.二 、完毕过滤

在customFilters.js文件中创设七个新的过滤器。

angular.module("customFilters", [])

.filter("unique", function () {

return function (data, propertyName) {

if (angular.isArray(data) && angular.isString(propertyName)) {

var results = [];

var keys = {};

for (var i = 0; i < data.length; i++) {

var val = data[i][propertyName];

ChAPTeR6 ■SPORTSSTORe: A ReAl APPlICATIOn

144

if (angular.isUndefined(keys[val])) {

keys[val] = true;

results.push(val);

}

}

return results;

} else {

return data;

}

}

})

.filter("range", function ($filter) {

return function (data, page, size) {

if (angular.isArray(data) && angular.isNumber(page) && angular.isNumber(size)) {

var start_index = (page 1) * size;

if (data.length < start_index) {

return [];

} else {

return $filter("limitTo")(data.splice(start_index), size);

}

} else {

return data;

}

}

})

.filter("pageCount", function () {

return function (data, size) {

if (angular.isArray(data)) {

var result = [];

for (var i = 0; i < Math.ceil(data.length / size) ; i++) {

result.push(i);

}

return result;

} else {

return data;

}

}

});

先是个新的过滤器,叫做range,从1个数组中回到一队列成分,代表出品页。过滤器接收参数,当前被入选的页(用于申明range的开始index),和page
size(用于申明end index)。

Range过滤器不是越发幽默,分歧于小编早就在听从上提供的三个内建过滤器,叫做limitTo,它从2个数组中,重临内定编号的项。要动用该过滤器,小编再$filter服务上定义了1个借助。它让我创立并利用filter的实例。笔者将在地14章解释详细,最重点的是那句声明:

return $filter("limitTo")(data.splice(start_index), size);

作者采纳的JavaScript
标准方法splice的结果是选项数据数组的一有个别,然后将它传递给limitTo过滤器,来挑选要在该页呈现的。limitTo过滤器确保遍历数组没至极,纵然内定的数字不可用,会回到多少个items。

第二个过滤器,pageCount,是一个龌龊的——但福利的——hack。Ng-repeat指令使得生成内容很粗略,但它依据数据数组工作。你无法,例如,让她再也钦点的次数。小编的过滤器总括出页码的一个数组。

小心:作者让过滤器的功能绕开受限制的ng-repeat指令,这是极度惊险的,可是个应急方法。更好的代表方式,会在第壹6,17章看到,让ng-repeat指令生成钦赐次数的元素。

3.5.叁 、更新视图

更新app.html。

<!DOCTYPE html>

<html ng-app="sportsStore">

<head>

<title>SportsStore</title>

<script src="angular.js"></script>

<link href="bootstrap.css" rel="stylesheet" />

<link href="bootstrap-theme.css" rel="stylesheet" />

<script>

angular.module("sportsStore", ["customFilters"]);

</script>

<script src="controllers/sportsStore.js"></script>

<script src="filters/customFilters.js"></script>

<script src="controllers/productListControllers.js"></script>

</head>

<body ng-controller="sportsStoreCtrl">

<div class="navbar navbar-inverse">

<a class="navbar-brand" href="#">SPORTS STORE</a>

</div>

<div class="panel panel-default row" ng-controller="productListCtrl">

<div class="col-xs-3">

<a ng-click="selectCategory()"

class="btn btn-block btn-default btn-lg">Home</a>

ChAPTeR6 ■SPORTSSTORe: A ReAl APPlICATIOn

146

<a ng-repeat="item in data.products | orderBy:’category’ | unique:’category’"

ng-click="selectCategory(item)" class=" btn btn-block btn-default btn-lg"

ng-class="getCategoryClass(item)">

{{item}}

</a>

</div>

<div class="col-xs-8">

<div class="well"

ng-repeat=

"item in data.products | filter:categoryFilterFn | range:selectedPage:pageSize">

<h3>

<strong>{{item.name}}</strong>

<span class="pull-right label label-primary">

{{item.price | currency}}

</span>

</h3>

<span class="lead">{{item.description}}</span>

</div>

<div class="pull-right btn-group">

<a ng-repeat=

"page in data.products | filter:categoryFilterFn | pageCount:pageSize"

ng-click="selectPage($index + 1)" class="btn btn-default"

ng-class="getPageClass($index + 1)">

{{$index + 1}}

</a>

</div>

</div>

</div>

</body>

</html>

首先处变更,是ng-repeat指令,生成产品列表,数据会通过range过滤器,过滤采纳当前页的成品。当前页的周详,和每页产品的多寡,使用作者定义在控制器scope上值作为参数,传递给过滤器。

其次处改动,是添加了领航按钮。小编利用ng-repeat指令,总结出当下相中的归类,有多少页产品,传递结果给pageCount过滤器,那会招致ng-repeat指令生成不易数量的导航页按钮。当前选中的页,通过ng-class指令表明,通过ng-click指令,页面变化。

 

 

 

 

 

 

 

 

 

相关文章